summary refs log tree commit diff
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Kconfig5
-rw-r--r--drivers/acpi/button.c206
-rw-r--r--drivers/acpi/dispatcher/dswload.c6
-rw-r--r--drivers/acpi/ec.c907
-rw-r--r--drivers/acpi/hotkey.c690
-rw-r--r--drivers/acpi/motherboard.c2
-rw-r--r--drivers/acpi/osl.c6
-rw-r--r--drivers/acpi/pci_irq.c85
-rw-r--r--drivers/acpi/pci_link.c127
-rw-r--r--drivers/acpi/processor_idle.c32
10 files changed, 1526 insertions, 540 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 986410e7b483..ba13896cae40 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -133,9 +133,10 @@ config ACPI_HOTKEY
 	depends on ACPI_INTERPRETER
 	depends on EXPERIMENTAL
 	depends on !IA64_SGI_SN
-	default m
+	default n
 	help
-	ACPI generic hotkey
+	  Experimental consolidated hotkey driver.
+	  If you are unsure, say N.
 
 config ACPI_FAN
 	tristate "Fan"
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 0f45d45f05a0..8162fd0c21a7 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -26,6 +26,9 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 
@@ -33,6 +36,9 @@
 #define ACPI_BUTTON_COMPONENT		0x00080000
 #define ACPI_BUTTON_DRIVER_NAME		"ACPI Button Driver"
 #define ACPI_BUTTON_CLASS		"button"
+#define ACPI_BUTTON_FILE_INFO		"info"
+#define ACPI_BUTTON_FILE_STATE		"state"
+#define ACPI_BUTTON_TYPE_UNKNOWN	0x00
 #define ACPI_BUTTON_NOTIFY_STATUS	0x80
 
 #define ACPI_BUTTON_SUBCLASS_POWER	"power"
@@ -64,6 +70,8 @@ MODULE_LICENSE("GPL");
 
 static int acpi_button_add (struct acpi_device *device);
 static int acpi_button_remove (struct acpi_device *device, int type);
+static int acpi_button_info_open_fs(struct inode *inode, struct file *file);
+static int acpi_button_state_open_fs(struct inode *inode, struct file *file);
 
 static struct acpi_driver acpi_button_driver = {
 	.name =		ACPI_BUTTON_DRIVER_NAME,
@@ -82,6 +90,179 @@ struct acpi_button {
 	unsigned long		pushed;
 };
 
+static struct file_operations acpi_button_info_fops = {
+	.open		= acpi_button_info_open_fs,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static struct file_operations acpi_button_state_fops = {
+	.open		= acpi_button_state_open_fs,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+/* --------------------------------------------------------------------------
+                              FS Interface (/proc)
+   -------------------------------------------------------------------------- */
+
+static struct proc_dir_entry	*acpi_button_dir;
+
+static int acpi_button_info_seq_show(struct seq_file *seq, void *offset)
+{
+	struct acpi_button	*button = (struct acpi_button *) seq->private;
+
+	ACPI_FUNCTION_TRACE("acpi_button_info_seq_show");
+
+	if (!button || !button->device)
+		return_VALUE(0);
+
+	seq_printf(seq, "type:                    %s\n", 
+		acpi_device_name(button->device));
+
+	return_VALUE(0);
+}
+
+static int acpi_button_info_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_button_info_seq_show, PDE(inode)->data);
+}
+	
+static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
+{
+	struct acpi_button	*button = (struct acpi_button *) seq->private;
+	acpi_status		status;
+	unsigned long		state;
+
+	ACPI_FUNCTION_TRACE("acpi_button_state_seq_show");
+
+	if (!button || !button->device)
+		return_VALUE(0);
+
+	status = acpi_evaluate_integer(button->handle,"_LID",NULL,&state);
+	if (ACPI_FAILURE(status)) {
+		seq_printf(seq, "state:      unsupported\n");
+	}
+	else{
+		seq_printf(seq, "state:      %s\n", (state ? "open" : "closed")); 
+	}
+
+	return_VALUE(0);
+}
+
+static int acpi_button_state_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_button_state_seq_show, PDE(inode)->data);
+}
+
+static struct proc_dir_entry *acpi_power_dir;
+static struct proc_dir_entry *acpi_sleep_dir;
+static struct proc_dir_entry *acpi_lid_dir;
+
+static int
+acpi_button_add_fs (
+	struct acpi_device	*device)
+{
+	struct proc_dir_entry	*entry = NULL;
+	struct acpi_button	*button = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_button_add_fs");
+
+	if (!device || !acpi_driver_data(device))
+		return_VALUE(-EINVAL);
+
+	button = acpi_driver_data(device);
+
+	switch (button->type) {
+	case ACPI_BUTTON_TYPE_POWER:
+	case ACPI_BUTTON_TYPE_POWERF:
+		if (!acpi_power_dir)
+			acpi_power_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER, 
+				acpi_button_dir);
+		entry = acpi_power_dir;
+		break;
+	case ACPI_BUTTON_TYPE_SLEEP:
+	case ACPI_BUTTON_TYPE_SLEEPF:
+		if (!acpi_sleep_dir)
+			acpi_sleep_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP, 
+				acpi_button_dir);
+		entry = acpi_sleep_dir;
+		break;
+	case ACPI_BUTTON_TYPE_LID:
+		if (!acpi_lid_dir)
+			acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, 
+				acpi_button_dir);
+		entry = acpi_lid_dir;
+		break;
+	}
+
+	if (!entry)
+		return_VALUE(-ENODEV);
+	entry->owner = THIS_MODULE;
+
+	acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
+	if (!acpi_device_dir(device))
+		return_VALUE(-ENODEV);
+	acpi_device_dir(device)->owner = THIS_MODULE;
+
+	/* 'info' [R] */
+	entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
+		S_IRUGO, acpi_device_dir(device));
+	if (!entry)
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"Unable to create '%s' fs entry\n",
+			ACPI_BUTTON_FILE_INFO));
+	else {
+		entry->proc_fops = &acpi_button_info_fops;
+		entry->data = acpi_driver_data(device);
+		entry->owner = THIS_MODULE;
+	}
+
+	/* show lid state [R] */
+	if (button->type == ACPI_BUTTON_TYPE_LID) {
+		entry = create_proc_entry(ACPI_BUTTON_FILE_STATE,
+			S_IRUGO, acpi_device_dir(device));
+		if (!entry)
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				"Unable to create '%s' fs entry\n",
+				ACPI_BUTTON_FILE_INFO));
+		else {
+			entry->proc_fops = &acpi_button_state_fops;
+			entry->data = acpi_driver_data(device);
+			entry->owner = THIS_MODULE;
+		}
+	}
+
+	return_VALUE(0);
+}
+
+
+static int
+acpi_button_remove_fs (
+	struct acpi_device	*device)
+{
+	struct acpi_button	*button = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_button_remove_fs");
+
+	button = acpi_driver_data(device);
+	if (acpi_device_dir(device)) {
+		if (button->type == ACPI_BUTTON_TYPE_LID)
+			remove_proc_entry(ACPI_BUTTON_FILE_STATE,
+					     acpi_device_dir(device));
+		remove_proc_entry(ACPI_BUTTON_FILE_INFO,
+				     acpi_device_dir(device));
+
+		remove_proc_entry(acpi_device_bid(device),
+				     acpi_device_dir(device)->parent);
+		acpi_device_dir(device) = NULL;
+	}
+
+	return_VALUE(0);
+}
+
+
 /* --------------------------------------------------------------------------
                                 Driver Interface
    -------------------------------------------------------------------------- */
@@ -121,7 +302,8 @@ acpi_button_notify_fixed (
 	
 	ACPI_FUNCTION_TRACE("acpi_button_notify_fixed");
 
-	BUG_ON(!button);
+	if (!button)
+		return_ACPI_STATUS(AE_BAD_PARAMETER);
 
 	acpi_button_notify(button->handle, ACPI_BUTTON_NOTIFY_STATUS, button);
 
@@ -197,6 +379,10 @@ acpi_button_add (
 		goto end;
 	}
 
+	result = acpi_button_add_fs(device);
+	if (result)
+		goto end;
+
 	switch (button->type) {
 	case ACPI_BUTTON_TYPE_POWERF:
 		status = acpi_install_fixed_event_handler (
@@ -240,6 +426,7 @@ acpi_button_add (
 
 end:
 	if (result) {
+		acpi_button_remove_fs(device);
 		kfree(button);
 	}
 
@@ -280,6 +467,8 @@ acpi_button_remove (struct acpi_device *device, int type)
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 			"Error removing notify handler\n"));
 
+	acpi_button_remove_fs(device);	
+
 	kfree(button);
 
 	return_VALUE(0);
@@ -293,14 +482,20 @@ acpi_button_init (void)
 
 	ACPI_FUNCTION_TRACE("acpi_button_init");
 
+	acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
+	if (!acpi_button_dir)
+		return_VALUE(-ENODEV);
+	acpi_button_dir->owner = THIS_MODULE;
 	result = acpi_bus_register_driver(&acpi_button_driver);
 	if (result < 0) {
+		remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
 		return_VALUE(-ENODEV);
 	}
 
 	return_VALUE(0);
 }
 
+
 static void __exit
 acpi_button_exit (void)
 {
@@ -308,8 +503,17 @@ acpi_button_exit (void)
 
 	acpi_bus_unregister_driver(&acpi_button_driver);
 
+	if (acpi_power_dir) 
+		remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER, acpi_button_dir);
+	if (acpi_sleep_dir)
+		remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP, acpi_button_dir);
+	if (acpi_lid_dir)
+		remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
+	remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
+
 	return_VOID;
 }
 
+
 module_init(acpi_button_init);
 module_exit(acpi_button_exit);
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
index 1ac197ccfc80..d11620018421 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -491,12 +491,6 @@ acpi_ds_load2_begin_op (
 		if ((!(walk_state->op_info->flags & AML_NSOPCODE) &&
 			  (walk_state->opcode != AML_INT_NAMEPATH_OP)) ||
 			(!(walk_state->op_info->flags & AML_NAMED))) {
-			if ((walk_state->op_info->class == AML_CLASS_EXECUTE) ||
-				(walk_state->op_info->class == AML_CLASS_CONTROL)) {
-				ACPI_REPORT_WARNING ((
-					"Encountered executable code at module level, [%s]\n",
-					acpi_ps_get_opcode_name (walk_state->opcode)));
-			}
 			return_ACPI_STATUS (AE_OK);
 		}
 
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index fca4140a50a9..1ac5731d45e5 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -59,76 +59,186 @@ ACPI_MODULE_NAME		("acpi_ec")
 #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 */
+
 #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
 
-static int acpi_ec_add (struct acpi_device *device);
+#define EC_POLLING		0xFF
+#define EC_BURST		0x00
+
+
 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_burst_add ( struct acpi_device *device);
+static int acpi_ec_polling_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_add,
+				.add =		acpi_ec_polling_add,
 				.remove =	acpi_ec_remove,
 				.start =	acpi_ec_start,
 				.stop =		acpi_ec_stop,
 			},
 };
-
-struct acpi_ec {
-	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;
+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;
+	}burst;
+
+	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;
+       		spinlock_t                      lock;
+	}polling;
 };
 
+static int acpi_ec_polling_wait ( union acpi_ec *ec, u8 event); 
+static int acpi_ec_burst_wait(union acpi_ec *ec, unsigned int event);
+static int acpi_ec_polling_read ( union acpi_ec *ec, u8 address, u32 *data);
+static int acpi_ec_burst_read( union acpi_ec *ec, u8 address, u32 *data);
+static int acpi_ec_polling_write ( union acpi_ec *ec, u8 address, u8 data);
+static int acpi_ec_burst_write ( union acpi_ec *ec, u8 address, u8 data);
+static int acpi_ec_polling_query ( union acpi_ec *ec, u32 *data);
+static int acpi_ec_burst_query ( union acpi_ec *ec, u32 *data);
+static void acpi_ec_gpe_polling_query ( void *ec_cxt);
+static void acpi_ec_gpe_burst_query ( void *ec_cxt);
+static u32 acpi_ec_gpe_polling_handler ( void *data);
+static u32 acpi_ec_gpe_burst_handler ( void *data);
+static acpi_status __init
+acpi_fake_ecdt_polling_callback (
+	acpi_handle	handle,
+	u32		Level,
+	void		*context,
+	void		**retval);
+
+static acpi_status __init
+acpi_fake_ecdt_burst_callback (
+	acpi_handle	handle,
+	u32		Level,
+	void		*context,
+	void		**retval);
+
+static int __init
+acpi_ec_polling_get_real_ecdt(void);
+static int __init
+acpi_ec_burst_get_real_ecdt(void);
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
-static struct acpi_ec	*ec_ecdt;
+static union acpi_ec	*ec_ecdt;
 
 /* External interfaces use first EC only, so remember */
 static struct acpi_device *first_ec;
+static int acpi_ec_polling_mode = EC_POLLING;
 
 /* --------------------------------------------------------------------------
                              Transaction Management
    -------------------------------------------------------------------------- */
 
-static inline u32 acpi_ec_read_status(struct acpi_ec *ec)
+static inline u32 acpi_ec_read_status(union acpi_ec *ec)
 {
 	u32	status = 0;
 
-	acpi_hw_low_level_read(8, &status, &ec->status_addr);
+	acpi_hw_low_level_read(8, &status, &ec->common.status_addr);
 	return status;
 }
 
-static int acpi_ec_wait(struct acpi_ec *ec, unsigned int event)
+static int
+acpi_ec_wait (
+	union acpi_ec		*ec,
+	u8			event)
+{
+	if (acpi_ec_polling_mode) 
+		return acpi_ec_polling_wait (ec, event);
+	else
+		return acpi_ec_burst_wait (ec, event);
+}
+
+static int
+acpi_ec_polling_wait (
+	union acpi_ec		*ec,
+	u8			event)
+{
+	u32			acpi_ec_status = 0;
+	u32			i = ACPI_EC_UDELAY_COUNT;
+
+	if (!ec)
+		return -EINVAL;
+
+	/* Poll the EC status register waiting for the event to occur. */
+	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);
+		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);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return -ETIME;
+}
+static int acpi_ec_burst_wait(union acpi_ec *ec, unsigned int event)
 {
 	int	result = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_wait");
 
-	ec->expect_event = event;
+	ec->burst.expect_event = event;
 	smp_mb();
 
-	result = wait_event_interruptible_timeout(ec->wait,
-					!ec->expect_event,
+	result = wait_event_interruptible_timeout(ec->burst.wait,
+					!ec->burst.expect_event,
 					msecs_to_jiffies(ACPI_EC_DELAY));
 	
-	ec->expect_event = 0;
+	ec->burst.expect_event = 0;
 	smp_mb();
 
 	if (result < 0){
@@ -160,7 +270,7 @@ static int acpi_ec_wait(struct acpi_ec *ec, unsigned int event)
 
 static int
 acpi_ec_enter_burst_mode (
-	struct acpi_ec		*ec)
+	union acpi_ec		*ec)
 {
 	u32			tmp = 0;
 	int			status = 0;
@@ -170,43 +280,43 @@ acpi_ec_enter_burst_mode (
 	status = acpi_ec_read_status(ec);
 	if (status != -EINVAL &&
 		!(status & ACPI_EC_FLAG_BURST)){
-		acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->command_addr);
+		acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->common.command_addr);
 		status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
 		if (status){
-			acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+			acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 			return_VALUE(-EINVAL);
 		}
-		acpi_hw_low_level_read(8, &tmp, &ec->data_addr);
-		acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+		acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr);
+		acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 		if(tmp != 0x90 ) {/* Burst ACK byte*/
 			return_VALUE(-EINVAL);
 		}
 	}
 
-	atomic_set(&ec->leaving_burst , 0);
+	atomic_set(&ec->burst.leaving_burst , 0);
 	return_VALUE(0);
 }
 
 static int
 acpi_ec_leave_burst_mode (
-	struct acpi_ec		*ec)
+	union acpi_ec		*ec)
 {
 	int			status =0;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_leave_burst_mode");
 
-	atomic_set(&ec->leaving_burst , 1);
+	atomic_set(&ec->burst.leaving_burst , 1);
 	status = acpi_ec_read_status(ec);
 	if (status != -EINVAL &&
 		(status & ACPI_EC_FLAG_BURST)){
-		acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->command_addr);
+		acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr);
 		status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
 		if (status){
-			acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+			acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"------->wait fail\n"));
 			return_VALUE(-EINVAL);
 		}
-		acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+		acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 		status = acpi_ec_read_status(ec);
 	}
 
@@ -215,7 +325,131 @@ acpi_ec_leave_burst_mode (
 
 static int
 acpi_ec_read (
-	struct acpi_ec		*ec,
+	union acpi_ec		*ec,
+	u8			address,
+	u32			*data)
+{
+	if (acpi_ec_polling_mode) 
+		return acpi_ec_polling_read(ec, address, data);
+	else
+		return acpi_ec_burst_read(ec, address, data);
+}
+static int
+acpi_ec_write (
+	union acpi_ec		*ec,
+	u8			address,
+	u8			data)
+{
+	if (acpi_ec_polling_mode) 
+		return acpi_ec_polling_write(ec, address, data);
+	else
+		return acpi_ec_burst_write(ec, address, data);
+}
+static int
+acpi_ec_polling_read (
+	union acpi_ec		*ec,
+	u8			address,
+	u32			*data)
+{
+	acpi_status		status = AE_OK;
+	int			result = 0;
+	unsigned long		flags = 0;
+	u32			glk = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_ec_read");
+
+	if (!ec || !data)
+		return_VALUE(-EINVAL);
+
+	*data = 0;
+
+	if (ec->common.global_lock) {
+		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
+		if (ACPI_FAILURE(status))
+			return_VALUE(-ENODEV);
+	}
+
+	spin_lock_irqsave(&ec->polling.lock, flags);
+
+	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;
+
+	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));
+	
+end:
+	spin_unlock_irqrestore(&ec->polling.lock, flags);
+
+	if (ec->common.global_lock)
+		acpi_release_global_lock(glk);
+
+	return_VALUE(result);
+}
+
+
+static int
+acpi_ec_polling_write (
+	union acpi_ec		*ec,
+	u8			address,
+	u8			data)
+{
+	int			result = 0;
+	acpi_status		status = AE_OK;
+	unsigned long		flags = 0;
+	u32			glk = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_ec_write");
+
+	if (!ec)
+		return_VALUE(-EINVAL);
+
+	if (ec->common.global_lock) {
+		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
+		if (ACPI_FAILURE(status))
+			return_VALUE(-ENODEV);
+	}
+
+	spin_lock_irqsave(&ec->polling.lock, flags);
+
+	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:
+	spin_unlock_irqrestore(&ec->polling.lock, flags);
+
+	if (ec->common.global_lock)
+		acpi_release_global_lock(glk);
+
+	return_VALUE(result);
+}
+
+static int
+acpi_ec_burst_read (
+	union acpi_ec		*ec,
 	u8			address,
 	u32			*data)
 {
@@ -230,51 +464,51 @@ acpi_ec_read (
 retry:
 	*data = 0;
 
-	if (ec->global_lock) {
+	if (ec->common.global_lock) {
 		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
 		if (ACPI_FAILURE(status))
 			return_VALUE(-ENODEV);
 	}
 
 	WARN_ON(in_interrupt());
-	down(&ec->sem);
+	down(&ec->burst.sem);
 
 	if(acpi_ec_enter_burst_mode(ec))
 		goto end;
 
-	acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->command_addr);
+	acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->common.command_addr);
 	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+	acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 	if (status) {
 		goto end;
 	}
 
-	acpi_hw_low_level_write(8, address, &ec->data_addr);
+	acpi_hw_low_level_write(8, address, &ec->common.data_addr);
 	status= acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
 	if (status){
-		acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+		acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 		goto end;
 	}
 
-	acpi_hw_low_level_read(8, data, &ec->data_addr);
-	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+	acpi_hw_low_level_read(8, data, &ec->common.data_addr);
+	acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
 		*data, address));
 	
 end:
 	acpi_ec_leave_burst_mode(ec);
-	up(&ec->sem);
+	up(&ec->burst.sem);
 
-	if (ec->global_lock)
+	if (ec->common.global_lock)
 		acpi_release_global_lock(glk);
 
-	if(atomic_read(&ec->leaving_burst) == 2){
+	if(atomic_read(&ec->burst.leaving_burst) == 2){
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n"));
-		while(atomic_read(&ec->pending_gpe)){
+		while(atomic_read(&ec->burst.pending_gpe)){
 			msleep(1);	
 		}
-		acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+		acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 		goto retry;
 	}
 
@@ -283,8 +517,8 @@ end:
 
 
 static int
-acpi_ec_write (
-	struct acpi_ec		*ec,
+acpi_ec_burst_write (
+	union acpi_ec		*ec,
 	u8			address,
 	u8			data)
 {
@@ -297,14 +531,14 @@ acpi_ec_write (
 	if (!ec)
 		return_VALUE(-EINVAL);
 retry:
-	if (ec->global_lock) {
+	if (ec->common.global_lock) {
 		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
 		if (ACPI_FAILURE(status))
 			return_VALUE(-ENODEV);
 	}
 
 	WARN_ON(in_interrupt());
-	down(&ec->sem);
+	down(&ec->burst.sem);
 
 	if(acpi_ec_enter_burst_mode(ec))
 		goto end;
@@ -312,33 +546,33 @@ retry:
 	status = acpi_ec_read_status(ec);
 	if (status != -EINVAL &&
 		!(status & ACPI_EC_FLAG_BURST)){
-		acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->command_addr);
+		acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->common.command_addr);
 		status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
 		if (status)
 			goto end;
-		acpi_hw_low_level_read(8, &tmp, &ec->data_addr);
+		acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr);
 		if(tmp != 0x90 ) /* Burst ACK byte*/
 			goto end;
 	}
 	/*Now we are in burst mode*/
 
-	acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->command_addr);
+	acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->common.command_addr);
 	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+	acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 	if (status){
 		goto end;
 	}
 
-	acpi_hw_low_level_write(8, address, &ec->data_addr);
+	acpi_hw_low_level_write(8, address, &ec->common.data_addr);
 	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
 	if (status){
-		acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+		acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 		goto end;
 	}
 
-	acpi_hw_low_level_write(8, data, &ec->data_addr);
+	acpi_hw_low_level_write(8, data, &ec->common.data_addr);
 	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
-	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+	acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 	if (status)
 		goto end;
 
@@ -347,17 +581,17 @@ retry:
 
 end:
 	acpi_ec_leave_burst_mode(ec);
-	up(&ec->sem);
+	up(&ec->burst.sem);
 
-	if (ec->global_lock)
+	if (ec->common.global_lock)
 		acpi_release_global_lock(glk);
 
-	if(atomic_read(&ec->leaving_burst) == 2){
+	if(atomic_read(&ec->burst.leaving_burst) == 2){
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n"));
-		while(atomic_read(&ec->pending_gpe)){
+		while(atomic_read(&ec->burst.pending_gpe)){
 			msleep(1);	
 		}
-		acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+		acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 		goto retry;
 	}
 
@@ -370,7 +604,7 @@ end:
 int
 ec_read(u8 addr, u8 *val)
 {
-	struct acpi_ec *ec;
+	union acpi_ec *ec;
 	int err;
 	u32 temp_data;
 
@@ -393,7 +627,7 @@ EXPORT_SYMBOL(ec_read);
 int
 ec_write(u8 addr, u8 val)
 {
-	struct acpi_ec *ec;
+	union acpi_ec *ec;
 	int err;
 
 	if (!first_ec)
@@ -407,10 +641,66 @@ ec_write(u8 addr, u8 val)
 }
 EXPORT_SYMBOL(ec_write);
 
-
 static int
 acpi_ec_query (
-	struct acpi_ec		*ec,
+	union acpi_ec		*ec,
+	u32			*data)
+{
+	if (acpi_ec_polling_mode) 
+		return acpi_ec_polling_query(ec, data);
+	else
+		return acpi_ec_burst_query(ec, data);
+}
+static int
+acpi_ec_polling_query (
+	union acpi_ec		*ec,
+	u32			*data)
+{
+	int			result = 0;
+	acpi_status		status = AE_OK;
+	unsigned long		flags = 0;
+	u32			glk = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_ec_query");
+
+	if (!ec || !data)
+		return_VALUE(-EINVAL);
+
+	*data = 0;
+
+	if (ec->common.global_lock) {
+		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
+		if (ACPI_FAILURE(status))
+			return_VALUE(-ENODEV);
+	}
+
+	/*
+	 * 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).
+	 */
+	spin_lock_irqsave(&ec->polling.lock, flags);
+
+	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:
+	spin_unlock_irqrestore(&ec->polling.lock, flags);
+
+	if (ec->common.global_lock)
+		acpi_release_global_lock(glk);
+
+	return_VALUE(result);
+}
+static int
+acpi_ec_burst_query (
+	union acpi_ec		*ec,
 	u32			*data)
 {
 	int			status = 0;
@@ -422,13 +712,13 @@ acpi_ec_query (
 		return_VALUE(-EINVAL);
 	*data = 0;
 
-	if (ec->global_lock) {
+	if (ec->common.global_lock) {
 		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
 		if (ACPI_FAILURE(status))
 			return_VALUE(-ENODEV);
 	}
 
-	down(&ec->sem);
+	down(&ec->burst.sem);
 	if(acpi_ec_enter_burst_mode(ec))
 		goto end;
 	/*
@@ -436,28 +726,28 @@ acpi_ec_query (
 	 * 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->command_addr);
+	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){
-		acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+		acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 		goto end;
 	}
 
-	acpi_hw_low_level_read(8, data, &ec->data_addr);
-	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+	acpi_hw_low_level_read(8, data, &ec->common.data_addr);
+	acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 	if (!*data)
 		status = -ENODATA;
 
 end:
 	acpi_ec_leave_burst_mode(ec);
-	up(&ec->sem);
+	up(&ec->burst.sem);
 
-	if (ec->global_lock)
+	if (ec->common.global_lock)
 		acpi_release_global_lock(glk);
 
-	if(atomic_read(&ec->leaving_burst) == 2){
+	if(atomic_read(&ec->burst.leaving_burst) == 2){
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n"));
-		acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+		acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 		status = -ENODATA;
 	}
 	return_VALUE(status);
@@ -468,7 +758,7 @@ end:
                                 Event Management
    -------------------------------------------------------------------------- */
 
-struct acpi_ec_query_data {
+union acpi_ec_query_data {
 	acpi_handle		handle;
 	u8			data;
 };
@@ -477,7 +767,59 @@ static void
 acpi_ec_gpe_query (
 	void			*ec_cxt)
 {
-	struct acpi_ec		*ec = (struct acpi_ec *) ec_cxt;
+	if (acpi_ec_polling_mode) 
+		acpi_ec_gpe_polling_query(ec_cxt);
+	else
+		acpi_ec_gpe_burst_query(ec_cxt);
+}
+
+static void
+acpi_ec_gpe_polling_query (
+	void			*ec_cxt)
+{
+	union acpi_ec		*ec = (union acpi_ec *) ec_cxt;
+	u32			value = 0;
+	unsigned long		flags = 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'};
+
+	ACPI_FUNCTION_TRACE("acpi_ec_gpe_query");
+
+	if (!ec_cxt)
+		goto end;
+
+	spin_lock_irqsave(&ec->polling.lock, flags);
+	acpi_hw_low_level_read(8, &value, &ec->common.command_addr);
+	spin_unlock_irqrestore(&ec->polling.lock, flags);
+
+	/* 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)];
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
+
+	acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL);
+
+end:	
+	acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
+}
+static void
+acpi_ec_gpe_burst_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'};
@@ -497,9 +839,9 @@ acpi_ec_gpe_query (
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
 
-	acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
+	acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL);
 end:	
-	atomic_dec(&ec->pending_gpe);
+	atomic_dec(&ec->burst.pending_gpe);
 	return;
 }
 
@@ -507,48 +849,77 @@ static u32
 acpi_ec_gpe_handler (
 	void			*data)
 {
+	if (acpi_ec_polling_mode) 
+		return acpi_ec_gpe_polling_handler(data);
+	else
+		return acpi_ec_gpe_burst_handler(data);	
+}
+static u32
+acpi_ec_gpe_polling_handler (
+	void			*data)
+{
+	acpi_status		status = AE_OK;
+	union acpi_ec		*ec = (union acpi_ec *) data;
+
+	if (!ec)
+		return ACPI_INTERRUPT_NOT_HANDLED;
+
+	acpi_disable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
+
+	status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
+		acpi_ec_gpe_query, ec);
+
+	if (status == AE_OK)
+		return ACPI_INTERRUPT_HANDLED;
+	else
+		return ACPI_INTERRUPT_NOT_HANDLED;
+}
+static u32
+acpi_ec_gpe_burst_handler (
+	void			*data)
+{
 	acpi_status		status = AE_OK;
 	u32			value;
-	struct acpi_ec		*ec = (struct acpi_ec *) data;
+	union acpi_ec		*ec = (union acpi_ec *) data;
 
 	if (!ec)
 		return ACPI_INTERRUPT_NOT_HANDLED;
 
-	acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
+	acpi_disable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
 
 	value = acpi_ec_read_status(ec);
 
 	if((value & ACPI_EC_FLAG_IBF) &&
 		!(value & ACPI_EC_FLAG_BURST) &&
-			(atomic_read(&ec->leaving_burst) == 0)) { 
+			(atomic_read(&ec->burst.leaving_burst) == 0)) { 
 	/*
 	 * the embedded controller disables 
 	 * burst mode for any reason other 
 	 * than the burst disable command
 	 * to process critical event.
 	 */
-		atomic_set(&ec->leaving_burst , 2); /* block current pending transaction
+		atomic_set(&ec->burst.leaving_burst , 2); /* block current pending transaction
 					and retry */
-		wake_up(&ec->wait);
+		wake_up(&ec->burst.wait);
 	}else {
-		if ((ec->expect_event == ACPI_EC_EVENT_OBF &&
+		if ((ec->burst.expect_event == ACPI_EC_EVENT_OBF &&
 				(value & ACPI_EC_FLAG_OBF)) ||
-	    			(ec->expect_event == ACPI_EC_EVENT_IBE &&
+	    			(ec->burst.expect_event == ACPI_EC_EVENT_IBE &&
 				!(value & ACPI_EC_FLAG_IBF))) {
-			ec->expect_event = 0;
-			wake_up(&ec->wait);
+			ec->burst.expect_event = 0;
+			wake_up(&ec->burst.wait);
 			return ACPI_INTERRUPT_HANDLED;
 		}
 	}
 
 	if (value & ACPI_EC_FLAG_SCI){
-		atomic_add(1, &ec->pending_gpe) ;
+		atomic_add(1, &ec->burst.pending_gpe) ;
 		status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
 						acpi_ec_gpe_query, ec);
 		return status == AE_OK ?
 		ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
 	} 
-	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
+	acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
 	return status == AE_OK ?
 		ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
 }
@@ -585,7 +956,7 @@ acpi_ec_space_handler (
 	void			*region_context)
 {
 	int			result = 0;
-	struct acpi_ec		*ec = NULL;
+	union acpi_ec		*ec = NULL;
 	u64			temp = *value;
 	acpi_integer		f_v = 0;
 	int 			i = 0;
@@ -600,7 +971,7 @@ acpi_ec_space_handler (
 		return_VALUE(AE_BAD_PARAMETER);
 	}
 
-	ec = (struct acpi_ec *) handler_context;
+	ec = (union acpi_ec *) handler_context;
 
 next_byte:
 	switch (function) {
@@ -661,7 +1032,7 @@ static struct proc_dir_entry	*acpi_ec_dir;
 static int
 acpi_ec_read_info (struct seq_file *seq, void *offset)
 {
-	struct acpi_ec		*ec = (struct acpi_ec *) seq->private;
+	union acpi_ec		*ec = (union acpi_ec *) seq->private;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_read_info");
 
@@ -669,12 +1040,12 @@ acpi_ec_read_info (struct seq_file *seq, void *offset)
 		goto end;
 
 	seq_printf(seq, "gpe bit:                 0x%02x\n",
-		(u32) ec->gpe_bit);
+		(u32) ec->common.gpe_bit);
 	seq_printf(seq, "ports:                   0x%02x, 0x%02x\n",
-		(u32) ec->status_addr.address, (u32) ec->data_addr.address);
+		(u32) ec->common.status_addr.address, (u32) ec->common.data_addr.address);
 	seq_printf(seq, "use global lock:         %s\n",
-		ec->global_lock?"yes":"no");
-	acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+		ec->common.global_lock?"yes":"no");
+	acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 
 end:
 	return_VALUE(0);
@@ -697,7 +1068,7 @@ static int
 acpi_ec_add_fs (
 	struct acpi_device	*device)
 {
-	struct proc_dir_entry	*entry;
+	struct proc_dir_entry	*entry = NULL;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_add_fs");
 
@@ -744,13 +1115,14 @@ acpi_ec_remove_fs (
                                Driver Interface
    -------------------------------------------------------------------------- */
 
+
 static int
-acpi_ec_add (
+acpi_ec_polling_add (
 	struct acpi_device	*device)
 {
-	int			result;
-	acpi_status		status;
-	struct acpi_ec		*ec;
+	int			result = 0;
+	acpi_status		status = AE_OK;
+	union acpi_ec		*ec = NULL;
 	unsigned long		uid;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_add");
@@ -758,39 +1130,107 @@ acpi_ec_add (
 	if (!device)
 		return_VALUE(-EINVAL);
 
-	ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+	ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
 	if (!ec)
 		return_VALUE(-ENOMEM);
-	memset(ec, 0, sizeof(struct acpi_ec));
-
-	ec->handle = device->handle;
-	ec->uid = -1;
- 	atomic_set(&ec->pending_gpe, 0);
- 	atomic_set(&ec->leaving_burst , 1);
- 	init_MUTEX(&ec->sem);
- 	init_waitqueue_head(&ec->wait);
+	memset(ec, 0, sizeof(union acpi_ec));
+
+	ec->common.handle = device->handle;
+	ec->common.uid = -1;
+	spin_lock_init(&ec->polling.lock);
 	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->handle, "_GLK", NULL, &ec->global_lock);
+	acpi_evaluate_integer(ec->common.handle, "_GLK", NULL, &ec->common.global_lock);
 
 	/* If our UID matches the UID for the ECDT-enumerated EC,
 	   we now have the *real* EC info, so kill the makeshift one.*/
-	acpi_evaluate_integer(ec->handle, "_UID", NULL, &uid);
-	if (ec_ecdt && ec_ecdt->uid == uid) {
+	acpi_evaluate_integer(ec->common.handle, "_UID", NULL, &uid);
+	if (ec_ecdt && ec_ecdt->common.uid == uid) {
 		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)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"Error obtaining GPE bit assignment\n"));
+		result = -ENODEV;
+		goto end;
+	}
 
-		acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler);
+	result = acpi_ec_add_fs(device);
+	if (result)
+		goto end;
+
+	printk(KERN_INFO PREFIX "%s [%s] (gpe %d)\n",
+		acpi_device_name(device), acpi_device_bid(device),
+		(u32) ec->common.gpe_bit);
+
+	if (!first_ec)
+		first_ec = device;
+
+end:
+	if (result)
+		kfree(ec);
+
+	return_VALUE(result);
+}
+static int
+acpi_ec_burst_add (
+	struct acpi_device	*device)
+{
+	int			result = 0;
+	acpi_status		status = AE_OK;
+	union acpi_ec		*ec = NULL;
+	unsigned long		uid;
+
+	ACPI_FUNCTION_TRACE("acpi_ec_add");
+
+	if (!device)
+		return_VALUE(-EINVAL);
+
+	ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+	if (!ec)
+		return_VALUE(-ENOMEM);
+	memset(ec, 0, sizeof(union acpi_ec));
+
+	ec->common.handle = device->handle;
+	ec->common.uid = -1;
+ 	atomic_set(&ec->burst.pending_gpe, 0);
+ 	atomic_set(&ec->burst.leaving_burst , 1);
+ 	init_MUTEX(&ec->burst.sem);
+ 	init_waitqueue_head(&ec->burst.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);
+
+	/* If our UID matches the UID for the ECDT-enumerated EC,
+	   we now have the *real* EC info, so kill the makeshift one.*/
+	acpi_evaluate_integer(ec->common.handle, "_UID", NULL, &uid);
+	if (ec_ecdt && ec_ecdt->common.uid == uid) {
+		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->handle, "_GPE", NULL, &ec->gpe_bit);
+	status = acpi_evaluate_integer(ec->common.handle, "_GPE", NULL, &ec->common.gpe_bit);
 	if (ACPI_FAILURE(status)) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 			"Error obtaining GPE bit assignment\n"));
@@ -804,7 +1244,7 @@ acpi_ec_add (
 
 	printk(KERN_INFO PREFIX "%s [%s] (gpe %d)\n",
 		acpi_device_name(device), acpi_device_bid(device),
-		(u32) ec->gpe_bit);
+		(u32) ec->common.gpe_bit);
 
 	if (!first_ec)
 		first_ec = device;
@@ -822,7 +1262,7 @@ acpi_ec_remove (
 	struct acpi_device	*device,
 	int			type)
 {
-	struct acpi_ec		*ec;
+	union acpi_ec		*ec = NULL;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_remove");
 
@@ -844,7 +1284,7 @@ acpi_ec_io_ports (
 	struct acpi_resource	*resource,
 	void			*context)
 {
-	struct acpi_ec		*ec = (struct acpi_ec *) context;
+	union acpi_ec		*ec = (union acpi_ec *) context;
 	struct acpi_generic_address *addr;
 
 	if (resource->id != ACPI_RSTYPE_IO) {
@@ -856,10 +1296,10 @@ acpi_ec_io_ports (
 	 * the second address region returned is the status/command
 	 * port.
 	 */
-	if (ec->data_addr.register_bit_width == 0) {
-		addr = &ec->data_addr;
-	} else if (ec->command_addr.register_bit_width == 0) {
-		addr = &ec->command_addr;
+	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;
 	} else {
 		return AE_CTRL_TERMINATE;
 	}
@@ -877,8 +1317,8 @@ static int
 acpi_ec_start (
 	struct acpi_device	*device)
 {
-	acpi_status		status;
-	struct acpi_ec		*ec;
+	acpi_status		status = AE_OK;
+	union acpi_ec		*ec = NULL;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_start");
 
@@ -893,35 +1333,36 @@ acpi_ec_start (
 	/*
 	 * Get I/O port addresses. Convert to GAS format.
 	 */
-	status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
+	status = acpi_walk_resources(ec->common.handle, METHOD_NAME__CRS,
 		acpi_ec_io_ports, ec);
-	if (ACPI_FAILURE(status) || ec->command_addr.register_bit_width == 0) {
+	if (ACPI_FAILURE(status) || ec->common.command_addr.register_bit_width == 0) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error getting I/O port addresses"));
 		return_VALUE(-ENODEV);
 	}
 
-	ec->status_addr = ec->command_addr;
+	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->gpe_bit, (u32) ec->command_addr.address,
-		(u32) ec->data_addr.address));
+		(u32) ec->common.gpe_bit, (u32) ec->common.command_addr.address,
+		(u32) ec->common.data_addr.address));
+
 
 	/*
 	 * Install GPE handler
 	 */
-	status = acpi_install_gpe_handler(NULL, ec->gpe_bit,
+	status = acpi_install_gpe_handler(NULL, ec->common.gpe_bit,
 		ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec);
 	if (ACPI_FAILURE(status)) {
 		return_VALUE(-ENODEV);
 	}
-	acpi_set_gpe_type (NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
-	acpi_enable_gpe (NULL, ec->gpe_bit, ACPI_NOT_ISR);
+	acpi_set_gpe_type (NULL, ec->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME);
+	acpi_enable_gpe (NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
 
-	status = acpi_install_address_space_handler (ec->handle,
+	status = acpi_install_address_space_handler (ec->common.handle,
 			ACPI_ADR_SPACE_EC, &acpi_ec_space_handler,
 			&acpi_ec_space_setup, ec);
 	if (ACPI_FAILURE(status)) {
-		acpi_remove_gpe_handler(NULL, ec->gpe_bit, &acpi_ec_gpe_handler);
+		acpi_remove_gpe_handler(NULL, ec->common.gpe_bit, &acpi_ec_gpe_handler);
 		return_VALUE(-ENODEV);
 	}
 
@@ -934,8 +1375,8 @@ acpi_ec_stop (
 	struct acpi_device	*device,
 	int			type)
 {
-	acpi_status		status;
-	struct acpi_ec		*ec;
+	acpi_status		status = AE_OK;
+	union acpi_ec		*ec = NULL;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_stop");
 
@@ -944,12 +1385,12 @@ acpi_ec_stop (
 
 	ec = acpi_driver_data(device);
 
-	status = acpi_remove_address_space_handler(ec->handle,
+	status = acpi_remove_address_space_handler(ec->common.handle,
 		ACPI_ADR_SPACE_EC, &acpi_ec_space_handler);
 	if (ACPI_FAILURE(status))
 		return_VALUE(-ENODEV);
 
-	status = acpi_remove_gpe_handler(NULL, ec->gpe_bit, &acpi_ec_gpe_handler);
+	status = acpi_remove_gpe_handler(NULL, ec->common.gpe_bit, &acpi_ec_gpe_handler);
 	if (ACPI_FAILURE(status))
 		return_VALUE(-ENODEV);
 
@@ -963,26 +1404,76 @@ acpi_fake_ecdt_callback (
 	void		*context,
 	void		**retval)
 {
+
+	if (acpi_ec_polling_mode)
+		return acpi_fake_ecdt_polling_callback(handle,
+			Level, context, retval);
+	else
+		return acpi_fake_ecdt_burst_callback(handle,
+			Level, context, retval);
+}
+
+static acpi_status __init
+acpi_fake_ecdt_polling_callback (
+	acpi_handle	handle,
+	u32		Level,
+	void		*context,
+	void		**retval)
+{
 	acpi_status	status;
 
 	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
 		acpi_ec_io_ports, ec_ecdt);
 	if (ACPI_FAILURE(status))
 		return status;
-	ec_ecdt->status_addr = ec_ecdt->command_addr;
+	ec_ecdt->common.status_addr = ec_ecdt->common.command_addr;
 
-	ec_ecdt->uid = -1;
-	acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
+	ec_ecdt->common.uid = -1;
+	acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid);
 
-	status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe_bit);
+	status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->common.gpe_bit);
 	if (ACPI_FAILURE(status))
 		return status;
-	ec_ecdt->global_lock = TRUE;
-	ec_ecdt->handle = handle;
+	spin_lock_init(&ec_ecdt->polling.lock);
+	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->gpe_bit, (u32) ec_ecdt->command_addr.address,
-		(u32) ec_ecdt->data_addr.address);
+		(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_burst_callback (
+	acpi_handle	handle,
+	u32		Level,
+	void		*context,
+	void		**retval)
+{
+	acpi_status	status;
+
+	init_MUTEX(&ec_ecdt->burst.sem);
+	init_waitqueue_head(&ec_ecdt->burst.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);
 
 	return AE_CTRL_TERMINATE;
 }
@@ -1005,12 +1496,12 @@ acpi_ec_fake_ecdt(void)
 
 	printk(KERN_INFO PREFIX "Try to make an fake ECDT\n");
 
-	ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+	ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
 	if (!ec_ecdt) {
 		ret = -ENOMEM;
 		goto error;
 	}
-	memset(ec_ecdt, 0, sizeof(struct acpi_ec));
+	memset(ec_ecdt, 0, sizeof(union acpi_ec));
 
 	status = acpi_get_devices (ACPI_EC_HID,
 				acpi_fake_ecdt_callback,
@@ -1031,6 +1522,60 @@ error:
 static int __init
 acpi_ec_get_real_ecdt(void)
 {
+	if (acpi_ec_polling_mode)
+		return acpi_ec_polling_get_real_ecdt();
+	else
+		return acpi_ec_burst_get_real_ecdt();
+}
+
+static int __init
+acpi_ec_polling_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));
+
+	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;
+	spin_lock_init(&ec_ecdt->polling.lock);
+	/* 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");
+	kfree(ec_ecdt);
+	ec_ecdt = NULL;
+
+	return -ENODEV;
+}
+
+
+static int __init
+acpi_ec_burst_get_real_ecdt(void)
+{
 	acpi_status		status;
 	struct acpi_table_ecdt 	*ecdt_ptr;
 
@@ -1044,22 +1589,22 @@ acpi_ec_get_real_ecdt(void)
 	/*
 	 * Generate a temporary ec context to use until the namespace is scanned
 	 */
-	ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+	ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
 	if (!ec_ecdt)
 		return -ENOMEM;
-	memset(ec_ecdt, 0, sizeof(struct acpi_ec));
-
- 	init_MUTEX(&ec_ecdt->sem);
- 	init_waitqueue_head(&ec_ecdt->wait);
-	ec_ecdt->command_addr = ecdt_ptr->ec_control;
-	ec_ecdt->status_addr = ecdt_ptr->ec_control;
-	ec_ecdt->data_addr = ecdt_ptr->ec_data;
-	ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
+	memset(ec_ecdt, 0, sizeof(union acpi_ec));
+
+ 	init_MUTEX(&ec_ecdt->burst.sem);
+ 	init_waitqueue_head(&ec_ecdt->burst.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->global_lock = TRUE;
-	ec_ecdt->uid = ecdt_ptr->uid;
+	ec_ecdt->common.global_lock = TRUE;
+	ec_ecdt->common.uid = ecdt_ptr->uid;
 
-	status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
+	status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle);
 	if (ACPI_FAILURE(status)) {
 		goto error;
 	}
@@ -1092,20 +1637,20 @@ acpi_ec_ecdt_probe (void)
 	/*
 	 * Install GPE handler
 	 */
-	status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit,
+	status = acpi_install_gpe_handler(NULL, ec_ecdt->common.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->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
-	acpi_enable_gpe (NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR);
+	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);
 
 	status = acpi_install_address_space_handler (ACPI_ROOT_OBJECT,
 			ACPI_ADR_SPACE_EC, &acpi_ec_space_handler,
 			&acpi_ec_space_setup, ec_ecdt);
 	if (ACPI_FAILURE(status)) {
-		acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
+		acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
 			&acpi_ec_gpe_handler);
 		goto error;
 	}
@@ -1123,7 +1668,7 @@ error:
 
 static int __init acpi_ec_init (void)
 {
-	int			result;
+	int			result = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_init");
 
@@ -1166,4 +1711,24 @@ static int __init acpi_fake_ecdt_setup(char *str)
 	acpi_fake_ecdt_enabled = 1;
 	return 0;
 }
+
 __setup("acpi_fake_ecdt", acpi_fake_ecdt_setup);
+static int __init acpi_ec_set_polling_mode(char *str)
+{
+	int burst;
+
+	if (!get_option(&str, &burst))
+		return 0;
+
+	if (burst) {
+		acpi_ec_polling_mode = EC_BURST;
+		acpi_ec_driver.ops.add = acpi_ec_burst_add;
+	} else {
+		acpi_ec_polling_mode = EC_POLLING;
+		acpi_ec_driver.ops.add = acpi_ec_polling_add;
+	}
+	printk(KERN_INFO PREFIX "EC %s mode.\n",
+		burst ? "burst": "polling");
+	return 0;
+}
+__setup("ec_burst=", acpi_ec_set_polling_mode);
diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c
index babdf762eadb..1f76a40badec 100644
--- a/drivers/acpi/hotkey.c
+++ b/drivers/acpi/hotkey.c
@@ -1,5 +1,5 @@
-/* 
- *  hotkey.c - ACPI Hotkey Driver ($Revision:$)
+/*
+ *  hotkey.c - ACPI Hotkey Driver ($Revision: 0.2 $)
  *
  *  Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
  *
@@ -51,17 +51,18 @@
 #define ACPI_HOTKEY_POLLING 0x2
 #define ACPI_UNDEFINED_EVENT    0xf
 
-#define MAX_CONFIG_RECORD_LEN   80
-#define MAX_NAME_PATH_LEN   80
-#define MAX_CALL_PARM       80
+#define RESULT_STR_LEN	    80
 
-#define IS_EVENT(e)       0xff	/* ((e) & 0x40000000)  */
-#define IS_POLL(e)      0xff	/* (~((e) & 0x40000000))  */
+#define ACTION_METHOD	0
+#define POLL_METHOD	1
 
+#define IS_EVENT(e)       	((e) <= 10000 && (e) >0)
+#define IS_POLL(e)      	((e) > 10000)
+#define IS_OTHERS(e)		((e)<=0 || (e)>=20000)
 #define _COMPONENT              ACPI_HOTKEY_COMPONENT
 ACPI_MODULE_NAME("acpi_hotkey")
 
-    MODULE_AUTHOR("luming.yu@intel.com");
+MODULE_AUTHOR("luming.yu@intel.com");
 MODULE_DESCRIPTION(ACPI_HOTK_NAME);
 MODULE_LICENSE("GPL");
 
@@ -114,7 +115,7 @@ struct acpi_event_hotkey {
 	char *action_method;	/* action method */
 };
 
-/* 
+/*
  * There are two ways to poll status
  * 1. directy call read_xxx method, without any arguments passed in
  * 2. call write_xxx method, with arguments passed in, you need
@@ -131,7 +132,7 @@ struct acpi_polling_hotkey {
 	char *poll_method;	/* poll method */
 	acpi_handle action_handle;	/* acpi handle attached action method */
 	char *action_method;	/* action method */
-	void *poll_result;	/* polling_result */
+	union acpi_object *poll_result;	/* polling_result */
 	struct proc_dir_entry *proc;
 };
 
@@ -162,20 +163,25 @@ static struct acpi_driver hotkey_driver = {
 		},
 };
 
+static void free_hotkey_device(union acpi_hotkey *key);
+static void free_hotkey_buffer(union acpi_hotkey *key);
+static void free_poll_hotkey_buffer(union acpi_hotkey *key);
 static int hotkey_open_config(struct inode *inode, struct file *file);
+static int hotkey_poll_open_config(struct inode *inode, struct file *file);
 static ssize_t hotkey_write_config(struct file *file,
 				   const char __user * buffer,
 				   size_t count, loff_t * data);
-static ssize_t hotkey_write_poll_config(struct file *file,
-					const char __user * buffer,
-					size_t count, loff_t * data);
 static int hotkey_info_open_fs(struct inode *inode, struct file *file);
 static int hotkey_action_open_fs(struct inode *inode, struct file *file);
 static ssize_t hotkey_execute_aml_method(struct file *file,
 					 const char __user * buffer,
 					 size_t count, loff_t * data);
 static int hotkey_config_seq_show(struct seq_file *seq, void *offset);
+static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset);
 static int hotkey_polling_open_fs(struct inode *inode, struct file *file);
+static union acpi_hotkey *get_hotkey_by_event(struct
+			      acpi_hotkey_list
+			      *hotkey_list, int event);
 
 /* event based config */
 static struct file_operations hotkey_config_fops = {
@@ -188,9 +194,9 @@ static struct file_operations hotkey_config_fops = {
 
 /* polling based config */
 static struct file_operations hotkey_poll_config_fops = {
-	.open = hotkey_open_config,
+	.open = hotkey_poll_open_config,
 	.read = seq_read,
-	.write = hotkey_write_poll_config,
+	.write = hotkey_write_config,
 	.llseek = seq_lseek,
 	.release = single_release,
 };
@@ -227,7 +233,7 @@ static int hotkey_info_seq_show(struct seq_file *seq, void *offset)
 {
 	ACPI_FUNCTION_TRACE("hotkey_info_seq_show");
 
-	seq_printf(seq, "Hotkey generic driver ver: %s", HOTKEY_ACPI_VERSION);
+	seq_printf(seq, "Hotkey generic driver ver: %s\n", HOTKEY_ACPI_VERSION);
 
 	return_VALUE(0);
 }
@@ -239,27 +245,35 @@ static int hotkey_info_open_fs(struct inode *inode, struct file *file)
 
 static char *format_result(union acpi_object *object)
 {
-	char *buf = (char *)kmalloc(sizeof(union acpi_object), GFP_KERNEL);
-
-	memset(buf, 0, sizeof(union acpi_object));
+	char *buf = NULL;
+	
+	buf = (char *)kmalloc(RESULT_STR_LEN, GFP_KERNEL);
+	if (buf)
+		memset(buf, 0, RESULT_STR_LEN);
+	else
+		goto do_fail;
 
 	/* Now, just support integer type */
 	if (object->type == ACPI_TYPE_INTEGER)
-		sprintf(buf, "%d", (u32) object->integer.value);
-
-	return buf;
+		sprintf(buf, "%d\n", (u32) object->integer.value);
+do_fail:
+	return (buf);
 }
 
 static int hotkey_polling_seq_show(struct seq_file *seq, void *offset)
 {
 	struct acpi_polling_hotkey *poll_hotkey =
 	    (struct acpi_polling_hotkey *)seq->private;
+	char *buf;
 
 	ACPI_FUNCTION_TRACE("hotkey_polling_seq_show");
 
-	if (poll_hotkey->poll_result)
-		seq_printf(seq, "%s", format_result(poll_hotkey->poll_result));
-
+	if (poll_hotkey->poll_result){
+		buf = format_result(poll_hotkey->poll_result);
+		if(buf)
+			seq_printf(seq, "%s", buf);
+		kfree(buf);
+	}
 	return_VALUE(0);
 }
 
@@ -276,19 +290,19 @@ static int hotkey_action_open_fs(struct inode *inode, struct file *file)
 /* Mapping external hotkey number to standardized hotkey event num */
 static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list)
 {
-	struct list_head *entries, *next;
-	int val = 0;
+	struct list_head *entries;
+	int val = -1;
 
 	ACPI_FUNCTION_TRACE("hotkey_get_internal_event");
 
-	list_for_each_safe(entries, next, list->entries) {
+	list_for_each(entries, list->entries) {
 		union acpi_hotkey *key =
 		    container_of(entries, union acpi_hotkey, entries);
 		if (key->link.hotkey_type == ACPI_HOTKEY_EVENT
-		    && key->event_hotkey.external_hotkey_num == event)
+		    && key->event_hotkey.external_hotkey_num == event){
 			val = key->link.hotkey_standard_num;
-		else
-			val = -1;
+			break;
+		}
 	}
 
 	return_VALUE(val);
@@ -306,7 +320,7 @@ acpi_hotkey_notify_handler(acpi_handle handle, u32 event, void *data)
 		return_VOID;
 
 	internal_event = hotkey_get_internal_event(event, &global_hotkey_list);
-	acpi_bus_generate_event(device, event, 0);
+	acpi_bus_generate_event(device, internal_event, 0);
 
 	return_VOID;
 }
@@ -329,13 +343,17 @@ static int auto_hotkey_remove(struct acpi_device *device, int type)
 static int create_polling_proc(union acpi_hotkey *device)
 {
 	struct proc_dir_entry *proc;
+	char  proc_name[80];
 	mode_t mode;
 
 	ACPI_FUNCTION_TRACE("create_polling_proc");
 	mode = S_IFREG | S_IRUGO | S_IWUGO;
 
-	proc = create_proc_entry(device->poll_hotkey.action_method,
-				 mode, hotkey_proc_dir);
+	sprintf(proc_name, "%d", device->link.hotkey_standard_num);
+	/*
+	strcat(proc_name, device->poll_hotkey.poll_method);
+	*/
+	proc = create_proc_entry(proc_name, mode, hotkey_proc_dir);
 
 	if (!proc) {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
@@ -353,23 +371,6 @@ static int create_polling_proc(union acpi_hotkey *device)
 	return_VALUE(0);
 }
 
-static int is_valid_acpi_path(const char *pathname)
-{
-	acpi_handle handle;
-	acpi_status status;
-	ACPI_FUNCTION_TRACE("is_valid_acpi_path");
-
-	status = acpi_get_handle(NULL, (char *)pathname, &handle);
-	return_VALUE(!ACPI_FAILURE(status));
-}
-
-static int is_valid_hotkey(union acpi_hotkey *device)
-{
-	ACPI_FUNCTION_TRACE("is_valid_hotkey");
-	/* Implement valid check */
-	return_VALUE(1);
-}
-
 static int hotkey_add(union acpi_hotkey *device)
 {
 	int status = 0;
@@ -378,15 +379,11 @@ static int hotkey_add(union acpi_hotkey *device)
 	ACPI_FUNCTION_TRACE("hotkey_add");
 
 	if (device->link.hotkey_type == ACPI_HOTKEY_EVENT) {
-		status =
-		    acpi_bus_get_device(device->event_hotkey.bus_handle, &dev);
-		if (status)
-			return_VALUE(status);
-
+		acpi_bus_get_device(device->event_hotkey.bus_handle, &dev);
 		status = acpi_install_notify_handler(dev->handle,
-						     ACPI_SYSTEM_NOTIFY,
+						     ACPI_DEVICE_NOTIFY,
 						     acpi_hotkey_notify_handler,
-						     device);
+						     dev);
 	} else			/* Add polling hotkey */
 		create_polling_proc(device);
 
@@ -409,84 +406,143 @@ static int hotkey_remove(union acpi_hotkey *device)
 		if (key->link.hotkey_standard_num ==
 		    device->link.hotkey_standard_num) {
 			list_del(&key->link.entries);
-			remove_proc_entry(key->poll_hotkey.action_method,
-					  hotkey_proc_dir);
+			free_hotkey_device(key);
 			global_hotkey_list.count--;
 			break;
 		}
 	}
+	kfree(device);
 	return_VALUE(0);
 }
 
-static void hotkey_update(union acpi_hotkey *key)
+static int  hotkey_update(union acpi_hotkey *key)
 {
-	struct list_head *entries, *next;
+	struct list_head *entries;
 
 	ACPI_FUNCTION_TRACE("hotkey_update");
 
-	list_for_each_safe(entries, next, global_hotkey_list.entries) {
-		union acpi_hotkey *key =
+	list_for_each(entries, global_hotkey_list.entries) {
+		union acpi_hotkey *tmp=
 		    container_of(entries, union acpi_hotkey, entries);
-		if (key->link.hotkey_standard_num ==
+		if (tmp->link.hotkey_standard_num ==
 		    key->link.hotkey_standard_num) {
-			key->event_hotkey.bus_handle =
-			    key->event_hotkey.bus_handle;
-			key->event_hotkey.external_hotkey_num =
-			    key->event_hotkey.external_hotkey_num;
-			key->event_hotkey.action_handle =
-			    key->event_hotkey.action_handle;
-			key->event_hotkey.action_method =
-			    key->event_hotkey.action_method;
+			if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
+				free_hotkey_buffer(tmp);
+				tmp->event_hotkey.bus_handle =
+			    		key->event_hotkey.bus_handle;
+				tmp->event_hotkey.external_hotkey_num =
+			    		key->event_hotkey.external_hotkey_num;
+				tmp->event_hotkey.action_handle =
+			    		key->event_hotkey.action_handle;
+				tmp->event_hotkey.action_method =
+			    		key->event_hotkey.action_method;
+				kfree(key);
+			} else {
+				/*
+				char  proc_name[80];
+
+				sprintf(proc_name, "%d", tmp->link.hotkey_standard_num);
+				strcat(proc_name, tmp->poll_hotkey.poll_method);
+				remove_proc_entry(proc_name,hotkey_proc_dir);
+				*/
+				free_poll_hotkey_buffer(tmp);
+				tmp->poll_hotkey.poll_handle =
+					key->poll_hotkey.poll_handle;
+				tmp->poll_hotkey.poll_method =
+					key->poll_hotkey.poll_method;
+				tmp->poll_hotkey.action_handle =
+					key->poll_hotkey.action_handle;
+				tmp->poll_hotkey.action_method =
+					key->poll_hotkey.action_method;
+				tmp->poll_hotkey.poll_result =
+					key->poll_hotkey.poll_result;
+				/*
+				create_polling_proc(tmp);
+				*/
+				kfree(key);
+			}
+			return_VALUE(0);
 			break;
 		}
 	}
 
-	return_VOID;
+	return_VALUE(-ENODEV);
 }
 
 static void free_hotkey_device(union acpi_hotkey *key)
 {
 	struct acpi_device *dev;
-	int status;
 
 	ACPI_FUNCTION_TRACE("free_hotkey_device");
 
 	if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
-		status =
-		    acpi_bus_get_device(key->event_hotkey.bus_handle, &dev);
+		acpi_bus_get_device(key->event_hotkey.bus_handle, &dev);
 		if (dev->handle)
 			acpi_remove_notify_handler(dev->handle,
-						   ACPI_SYSTEM_NOTIFY,
+						   ACPI_DEVICE_NOTIFY,
 						   acpi_hotkey_notify_handler);
-	} else
-		remove_proc_entry(key->poll_hotkey.action_method,
-				  hotkey_proc_dir);
+		free_hotkey_buffer(key);
+	} else {
+		char  proc_name[80];
+
+		sprintf(proc_name, "%d", key->link.hotkey_standard_num);
+		/*
+		strcat(proc_name, key->poll_hotkey.poll_method);
+		*/
+		remove_proc_entry(proc_name,hotkey_proc_dir);
+		free_poll_hotkey_buffer(key);
+	}
 	kfree(key);
 	return_VOID;
 }
 
+static void
+free_hotkey_buffer(union acpi_hotkey *key)
+{
+	kfree(key->event_hotkey.action_method);
+}
+
+static void
+free_poll_hotkey_buffer(union acpi_hotkey *key)
+{
+	kfree(key->poll_hotkey.action_method);
+	kfree(key->poll_hotkey.poll_method);
+	kfree(key->poll_hotkey.poll_result);
+}
 static int
 init_hotkey_device(union acpi_hotkey *key, char *bus_str, char *action_str,
 		   char *method, int std_num, int external_num)
 {
+	acpi_handle	tmp_handle;
+	acpi_status status = AE_OK;
+
 	ACPI_FUNCTION_TRACE("init_hotkey_device");
 
+	if(std_num < 0 || IS_POLL(std_num) || !key )
+		goto do_fail;
+
+	if(!bus_str || !action_str || !method)
+		goto do_fail;
+
 	key->link.hotkey_type = ACPI_HOTKEY_EVENT;
 	key->link.hotkey_standard_num = std_num;
 	key->event_hotkey.flag = 0;
-	if (is_valid_acpi_path(bus_str))
-		acpi_get_handle((acpi_handle) 0,
-				bus_str, &(key->event_hotkey.bus_handle));
-	else
-		return_VALUE(-ENODEV);
-	key->event_hotkey.external_hotkey_num = external_num;
-	if (is_valid_acpi_path(action_str))
-		acpi_get_handle((acpi_handle) 0,
-				action_str, &(key->event_hotkey.action_handle));
-	key->event_hotkey.action_method = kmalloc(sizeof(method), GFP_KERNEL);
-	strcpy(key->event_hotkey.action_method, method);
+	key->event_hotkey.action_method = method;
 
-	return_VALUE(!is_valid_hotkey(key));
+	status = acpi_get_handle(NULL,bus_str, &(key->event_hotkey.bus_handle));
+	if(ACPI_FAILURE(status))
+		goto do_fail;
+	key->event_hotkey.external_hotkey_num = external_num;
+	status = acpi_get_handle(NULL,action_str, &(key->event_hotkey.action_handle));
+	if(ACPI_FAILURE(status))
+		goto do_fail;
+	status = acpi_get_handle(key->event_hotkey.action_handle,
+				method, &tmp_handle);
+	if (ACPI_FAILURE(status))
+		goto do_fail;
+	return_VALUE(AE_OK);
+do_fail:
+	return_VALUE(-ENODEV);
 }
 
 static int
@@ -495,34 +551,46 @@ init_poll_hotkey_device(union acpi_hotkey *key,
 			char *poll_method,
 			char *action_str, char *action_method, int std_num)
 {
+	acpi_status status = AE_OK;
+	acpi_handle	tmp_handle;
+
 	ACPI_FUNCTION_TRACE("init_poll_hotkey_device");
 
+	if(std_num < 0 || IS_EVENT(std_num) || !key)
+		goto do_fail;
+
+	if(!poll_str || !poll_method || !action_str || !action_method)
+		goto do_fail;
+
 	key->link.hotkey_type = ACPI_HOTKEY_POLLING;
 	key->link.hotkey_standard_num = std_num;
 	key->poll_hotkey.flag = 0;
-	if (is_valid_acpi_path(poll_str))
-		acpi_get_handle((acpi_handle) 0,
-				poll_str, &(key->poll_hotkey.poll_handle));
-	else
-		return_VALUE(-ENODEV);
 	key->poll_hotkey.poll_method = poll_method;
-	if (is_valid_acpi_path(action_str))
-		acpi_get_handle((acpi_handle) 0,
-				action_str, &(key->poll_hotkey.action_handle));
-	key->poll_hotkey.action_method =
-	    kmalloc(sizeof(action_method), GFP_KERNEL);
-	strcpy(key->poll_hotkey.action_method, action_method);
+	key->poll_hotkey.action_method = action_method;
+
+	status = acpi_get_handle(NULL,poll_str, &(key->poll_hotkey.poll_handle));
+	if(ACPI_FAILURE(status))
+		goto do_fail;
+	status = acpi_get_handle(key->poll_hotkey.poll_handle,
+				poll_method, &tmp_handle);
+        if (ACPI_FAILURE(status))
+       		goto do_fail;
+	status = acpi_get_handle(NULL,action_str, &(key->poll_hotkey.action_handle));
+	if (ACPI_FAILURE(status))
+		goto do_fail;
+	status = acpi_get_handle(key->poll_hotkey.action_handle,
+				action_method, &tmp_handle);
+	if (ACPI_FAILURE(status))
+		goto do_fail;
 	key->poll_hotkey.poll_result =
 	    (union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL);
-	return_VALUE(is_valid_hotkey(key));
+	if(!key->poll_hotkey.poll_result)
+		goto do_fail;
+	return_VALUE(AE_OK);
+do_fail:
+	return_VALUE(-ENODEV);
 }
 
-static int check_hotkey_valid(union acpi_hotkey *key,
-			      struct acpi_hotkey_list *list)
-{
-	ACPI_FUNCTION_TRACE("check_hotkey_valid");
-	return_VALUE(0);
-}
 
 static int hotkey_open_config(struct inode *inode, struct file *file)
 {
@@ -531,10 +599,17 @@ static int hotkey_open_config(struct inode *inode, struct file *file)
 		     (file, hotkey_config_seq_show, PDE(inode)->data));
 }
 
+static int hotkey_poll_open_config(struct inode *inode, struct file *file)
+{
+	ACPI_FUNCTION_TRACE("hotkey_poll_open_config");
+	return_VALUE(single_open
+		     (file, hotkey_poll_config_seq_show, PDE(inode)->data));
+}
+
 static int hotkey_config_seq_show(struct seq_file *seq, void *offset)
 {
 	struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
-	struct list_head *entries, *next;
+	struct list_head *entries;
 	char bus_name[ACPI_PATHNAME_MAX] = { 0 };
 	char action_name[ACPI_PATHNAME_MAX] = { 0 };
 	struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name };
@@ -542,10 +617,7 @@ static int hotkey_config_seq_show(struct seq_file *seq, void *offset)
 
 	ACPI_FUNCTION_TRACE(("hotkey_config_seq_show"));
 
-	if (!hotkey_list)
-		goto end;
-
-	list_for_each_safe(entries, next, hotkey_list->entries) {
+	list_for_each(entries, hotkey_list->entries) {
 		union acpi_hotkey *key =
 		    container_of(entries, union acpi_hotkey, entries);
 		if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
@@ -553,18 +625,37 @@ static int hotkey_config_seq_show(struct seq_file *seq, void *offset)
 				      ACPI_NAME_TYPE_MAX, &bus);
 			acpi_get_name(key->event_hotkey.action_handle,
 				      ACPI_NAME_TYPE_MAX, &act);
-			seq_printf(seq, "%s:%s:%s:%d:%d", bus_name,
+			seq_printf(seq, "%s:%s:%s:%d:%d\n", bus_name,
 				   action_name,
 				   key->event_hotkey.action_method,
 				   key->link.hotkey_standard_num,
 				   key->event_hotkey.external_hotkey_num);
-		} /* ACPI_HOTKEY_POLLING */
-		else {
+		}
+	}
+	seq_puts(seq, "\n");
+	return_VALUE(0);
+}
+
+static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset)
+{
+	struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
+	struct list_head *entries;
+	char bus_name[ACPI_PATHNAME_MAX] = { 0 };
+	char action_name[ACPI_PATHNAME_MAX] = { 0 };
+	struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name };
+	struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name };
+
+	ACPI_FUNCTION_TRACE(("hotkey_config_seq_show"));
+
+	list_for_each(entries, hotkey_list->entries) {
+		union acpi_hotkey *key =
+		    container_of(entries, union acpi_hotkey, entries);
+		if (key->link.hotkey_type == ACPI_HOTKEY_POLLING) {
 			acpi_get_name(key->poll_hotkey.poll_handle,
 				      ACPI_NAME_TYPE_MAX, &bus);
 			acpi_get_name(key->poll_hotkey.action_handle,
 				      ACPI_NAME_TYPE_MAX, &act);
-			seq_printf(seq, "%s:%s:%s:%s:%d", bus_name,
+			seq_printf(seq, "%s:%s:%s:%s:%d\n", bus_name,
 				   key->poll_hotkey.poll_method,
 				   action_name,
 				   key->poll_hotkey.action_method,
@@ -572,49 +663,83 @@ static int hotkey_config_seq_show(struct seq_file *seq, void *offset)
 		}
 	}
 	seq_puts(seq, "\n");
-      end:
 	return_VALUE(0);
 }
 
 static int
 get_parms(char *config_record,
 	  int *cmd,
-	  char *bus_handle,
-	  char *bus_method,
-	  char *action_handle,
-	  char *method, int *internal_event_num, int *external_event_num)
+	  char **bus_handle,
+	  char **bus_method,
+	  char **action_handle,
+	  char **method, int *internal_event_num, int *external_event_num)
 {
-	char *tmp, *tmp1;
+	char *tmp, *tmp1, count;
 	ACPI_FUNCTION_TRACE(("get_parms"));
 
 	sscanf(config_record, "%d", cmd);
 
+	if(*cmd == 1){
+		if(sscanf(config_record, "%d:%d", cmd, internal_event_num)!=2)
+			goto do_fail;
+		else
+			return (6);
+	}
 	tmp = strchr(config_record, ':');
+	if (!tmp)
+		goto do_fail;
 	tmp++;
 	tmp1 = strchr(tmp, ':');
-	strncpy(bus_handle, tmp, tmp1 - tmp);
-	bus_handle[tmp1 - tmp] = 0;
+	if (!tmp1)
+		goto do_fail;
+
+	count = tmp1 - tmp;
+	*bus_handle = (char *) kmalloc(count+1, GFP_KERNEL);
+	if(!*bus_handle)
+		goto do_fail;
+	strncpy(*bus_handle, tmp, count);
+	*(*bus_handle + count) = 0;
 
 	tmp = tmp1;
 	tmp++;
 	tmp1 = strchr(tmp, ':');
-	strncpy(bus_method, tmp, tmp1 - tmp);
-	bus_method[tmp1 - tmp] = 0;
+	if (!tmp1)
+		goto do_fail;
+	count = tmp1 - tmp;
+	*bus_method = (char *) kmalloc(count+1, GFP_KERNEL);
+	if(!*bus_method)
+		goto do_fail;
+	strncpy(*bus_method, tmp, count);
+	*(*bus_method + count) = 0;
 
 	tmp = tmp1;
 	tmp++;
 	tmp1 = strchr(tmp, ':');
-	strncpy(action_handle, tmp, tmp1 - tmp);
-	action_handle[tmp1 - tmp] = 0;
+	if (!tmp1)
+		goto do_fail;
+	count = tmp1 - tmp;
+	*action_handle = (char *) kmalloc(count+1, GFP_KERNEL);
+	strncpy(*action_handle, tmp, count);
+	*(*action_handle + count) = 0;
 
 	tmp = tmp1;
 	tmp++;
 	tmp1 = strchr(tmp, ':');
-	strncpy(method, tmp, tmp1 - tmp);
-	method[tmp1 - tmp] = 0;
+	if (!tmp1)
+		goto do_fail;
+	count = tmp1 - tmp;
+	*method = (char *) kmalloc(count+1, GFP_KERNEL);
+	if(!*method)
+		goto do_fail;
+	strncpy(*method, tmp, count);
+	*(*method + count) = 0;
+
+	if(sscanf(tmp1 + 1, "%d:%d", internal_event_num, external_event_num)<=0)
+		goto do_fail;
 
-	sscanf(tmp1 + 1, "%d:%d", internal_event_num, external_event_num);
 	return_VALUE(6);
+do_fail:
+	return_VALUE(-1);
 }
 
 /*  count is length for one input record */
@@ -622,135 +747,117 @@ static ssize_t hotkey_write_config(struct file *file,
 				   const char __user * buffer,
 				   size_t count, loff_t * data)
 {
-	struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
-	char config_record[MAX_CONFIG_RECORD_LEN];
-	char bus_handle[MAX_NAME_PATH_LEN];
-	char bus_method[MAX_NAME_PATH_LEN];
-	char action_handle[MAX_NAME_PATH_LEN];
-	char method[20];
+	char *config_record = NULL;
+	char *bus_handle = NULL;
+	char *bus_method = NULL;
+	char *action_handle = NULL;
+	char *method = NULL;
 	int cmd, internal_event_num, external_event_num;
 	int ret = 0;
 	union acpi_hotkey *key = NULL;
 
 	ACPI_FUNCTION_TRACE(("hotkey_write_config"));
 
-	if (!hotkey_list || count > MAX_CONFIG_RECORD_LEN) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid arguments\n"));
-		return_VALUE(-EINVAL);
-	}
+	config_record = (char *) kmalloc(count+1, GFP_KERNEL);
+	if(!config_record)
+		return_VALUE(-ENOMEM);
 
 	if (copy_from_user(config_record, buffer, count)) {
+		kfree(config_record);
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data \n"));
 		return_VALUE(-EINVAL);
 	}
-	config_record[count] = '\0';
+	config_record[count] = 0;
 
 	ret = get_parms(config_record,
 			&cmd,
-			bus_handle,
-			bus_method,
-			action_handle,
-			method, &internal_event_num, &external_event_num);
+			&bus_handle,
+			&bus_method,
+			&action_handle,
+			&method, &internal_event_num, &external_event_num);
+
+	kfree(config_record);
+	if(IS_OTHERS(internal_event_num))
+		goto do_fail;
 	if (ret != 6) {
+do_fail:	
+		kfree(bus_handle);
+		kfree(bus_method);
+		kfree(action_handle);
+		kfree(method);
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 				  "Invalid data format ret=%d\n", ret));
 		return_VALUE(-EINVAL);
 	}
 
 	key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL);
-	ret = init_hotkey_device(key, bus_handle, action_handle, method,
+	if(!key)
+		goto do_fail;
+	memset(key, 0, sizeof(union acpi_hotkey));
+	if(cmd == 1) {
+		union acpi_hotkey *tmp = NULL;
+		tmp = get_hotkey_by_event(&global_hotkey_list,
+				internal_event_num);
+		if(!tmp)
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid key"));
+		else
+			memcpy(key, tmp, sizeof(union acpi_hotkey));
+		goto cont_cmd;
+	}
+	if (IS_EVENT(internal_event_num)) {
+		kfree(bus_method);
+		ret = init_hotkey_device(key, bus_handle, action_handle, method,
 				 internal_event_num, external_event_num);
-
-	if (ret || check_hotkey_valid(key, hotkey_list)) {
+	} else
+		ret = init_poll_hotkey_device(key, bus_handle, bus_method,
+				      action_handle, method,
+				      internal_event_num);
+	if (ret) {
+		kfree(bus_handle);
+		kfree(action_handle);
+		if(IS_EVENT(internal_event_num))
+			free_hotkey_buffer(key);
+		else
+			free_poll_hotkey_buffer(key);
 		kfree(key);
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid hotkey \n"));
 		return_VALUE(-EINVAL);
 	}
-	switch (cmd) {
-	case 0:
-		hotkey_add(key);
-		break;
-	case 1:
-		hotkey_remove(key);
-		free_hotkey_device(key);
-		break;
-	case 2:
-		hotkey_update(key);
-		break;
-	default:
-		break;
-	}
-	return_VALUE(count);
-}
-
-/*  count is length for one input record */
-static ssize_t hotkey_write_poll_config(struct file *file,
-					const char __user * buffer,
-					size_t count, loff_t * data)
-{
-	struct seq_file *m = (struct seq_file *)file->private_data;
-	struct acpi_hotkey_list *hotkey_list =
-	    (struct acpi_hotkey_list *)m->private;
-
-	char config_record[MAX_CONFIG_RECORD_LEN];
-	char polling_handle[MAX_NAME_PATH_LEN];
-	char action_handle[MAX_NAME_PATH_LEN];
-	char poll_method[20], action_method[20];
-	int ret, internal_event_num, cmd, external_event_num;
-	union acpi_hotkey *key = NULL;
-
-	ACPI_FUNCTION_TRACE("hotkey_write_poll_config");
-
-	if (!hotkey_list || count > MAX_CONFIG_RECORD_LEN) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid arguments\n"));
-		return_VALUE(-EINVAL);
-	}
-
-	if (copy_from_user(config_record, buffer, count)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data \n"));
-		return_VALUE(-EINVAL);
-	}
-	config_record[count] = '\0';
 
-	ret = get_parms(config_record,
-			&cmd,
-			polling_handle,
-			poll_method,
-			action_handle,
-			action_method,
-			&internal_event_num, &external_event_num);
-
-	if (ret != 6) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
-		return_VALUE(-EINVAL);
-	}
+cont_cmd:
+	kfree(bus_handle);
+	kfree(action_handle);
 
-	key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL);
-	ret = init_poll_hotkey_device(key, polling_handle, poll_method,
-				      action_handle, action_method,
-				      internal_event_num);
-	if (ret || check_hotkey_valid(key, hotkey_list)) {
-		kfree(key);
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid hotkey \n"));
-		return_VALUE(-EINVAL);
-	}
 	switch (cmd) {
 	case 0:
-		hotkey_add(key);
+		if(get_hotkey_by_event(&global_hotkey_list,key->link.hotkey_standard_num))
+			goto fail_out;
+		else
+			hotkey_add(key);
 		break;
 	case 1:
 		hotkey_remove(key);
 		break;
 	case 2:
-		hotkey_update(key);
+		if(hotkey_update(key))
+			goto fail_out;
 		break;
 	default:
+		goto fail_out;
 		break;
 	}
 	return_VALUE(count);
+fail_out:
+	if(IS_EVENT(internal_event_num))
+		free_hotkey_buffer(key);
+	else
+		free_poll_hotkey_buffer(key);
+	kfree(key);
+	ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid key\n"));
+	return_VALUE(-EINVAL);
 }
 
-/*  
+/*
  * This function evaluates an ACPI method, given an int as parameter, the
  * method is searched within the scope of the handle, can be NULL. The output
  * of the method is written is output, which can also be NULL
@@ -775,7 +882,7 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
 	return_VALUE(status == AE_OK);
 }
 
-static int read_acpi_int(acpi_handle handle, const char *method, int *val)
+static int read_acpi_int(acpi_handle handle, const char *method, union acpi_object *val)
 {
 	struct acpi_buffer output;
 	union acpi_object out_obj;
@@ -786,62 +893,32 @@ static int read_acpi_int(acpi_handle handle, const char *method, int *val)
 	output.pointer = &out_obj;
 
 	status = acpi_evaluate_object(handle, (char *)method, NULL, &output);
-	*val = out_obj.integer.value;
+	if(val){
+		val->integer.value = out_obj.integer.value;
+		val->type = out_obj.type;
+	} else
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "null val pointer"));
 	return_VALUE((status == AE_OK)
 		     && (out_obj.type == ACPI_TYPE_INTEGER));
 }
 
-static acpi_handle
-get_handle_from_hotkeylist(struct acpi_hotkey_list *hotkey_list, int event_num)
+static union acpi_hotkey *get_hotkey_by_event(struct
+			      acpi_hotkey_list
+			      *hotkey_list, int event)
 {
-	struct list_head *entries, *next;
-
-	list_for_each_safe(entries, next, hotkey_list->entries) {
-		union acpi_hotkey *key =
-		    container_of(entries, union acpi_hotkey, entries);
-		if (key->link.hotkey_type == ACPI_HOTKEY_EVENT
-		    && key->link.hotkey_standard_num == event_num) {
-			return (key->event_hotkey.action_handle);
-		}
-	}
-	return (NULL);
-}
-
-static
-char *get_method_from_hotkeylist(struct acpi_hotkey_list *hotkey_list,
-				 int event_num)
-{
-	struct list_head *entries, *next;
-
-	list_for_each_safe(entries, next, hotkey_list->entries) {
-		union acpi_hotkey *key =
-		    container_of(entries, union acpi_hotkey, entries);
-
-		if (key->link.hotkey_type == ACPI_HOTKEY_EVENT &&
-		    key->link.hotkey_standard_num == event_num)
-			return (key->event_hotkey.action_method);
-	}
-	return (NULL);
-}
-
-static struct acpi_polling_hotkey *get_hotkey_by_event(struct
-						       acpi_hotkey_list
-						       *hotkey_list, int event)
-{
-	struct list_head *entries, *next;
+	struct list_head *entries;
 
-	list_for_each_safe(entries, next, hotkey_list->entries) {
+	list_for_each(entries, hotkey_list->entries) {
 		union acpi_hotkey *key =
 		    container_of(entries, union acpi_hotkey, entries);
-		if (key->link.hotkey_type == ACPI_HOTKEY_POLLING
-		    && key->link.hotkey_standard_num == event) {
-			return (&key->poll_hotkey);
+		if (key->link.hotkey_standard_num == event) {
+			return(key);
 		}
 	}
-	return (NULL);
+	return(NULL);
 }
 
-/*  
+/*
  * user call AML method interface:
  * Call convention:
  * echo "event_num: arg type : value"
@@ -854,48 +931,56 @@ static ssize_t hotkey_execute_aml_method(struct file *file,
 					 size_t count, loff_t * data)
 {
 	struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
-	char arg[MAX_CALL_PARM];
-	int event, type, value;
-
-	char *method;
-	acpi_handle handle;
+	char *arg;
+	int event,method_type,type, value;
+	union acpi_hotkey *key;
 
 	ACPI_FUNCTION_TRACE("hotkey_execte_aml_method");
 
-	if (!hotkey_list || count > MAX_CALL_PARM) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 1"));
-		return_VALUE(-EINVAL);
-	}
+	arg = (char *) kmalloc(count+1, GFP_KERNEL);
+	if(!arg)
+		return_VALUE(-ENOMEM);
+	arg[count]=0;
 
 	if (copy_from_user(arg, buffer, count)) {
+		kfree(arg);
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 2"));
 		return_VALUE(-EINVAL);
 	}
 
-	arg[count] = '\0';
-
-	if (sscanf(arg, "%d:%d:%d", &event, &type, &value) != 3) {
+	if (sscanf(arg, "%d:%d:%d:%d", &event, &method_type, &type, &value) != 4) {
+		kfree(arg);
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 3"));
 		return_VALUE(-EINVAL);
 	}
-
+	kfree(arg);
 	if (type == ACPI_TYPE_INTEGER) {
-		handle = get_handle_from_hotkeylist(hotkey_list, event);
-		method = (char *)get_method_from_hotkeylist(hotkey_list, event);
+		key = get_hotkey_by_event(hotkey_list, event);
+		if(!key)
+			goto do_fail;
 		if (IS_EVENT(event))
-			write_acpi_int(handle, method, value, NULL);
+			write_acpi_int(key->event_hotkey.action_handle,
+					key->event_hotkey.action_method, value, NULL);
 		else if (IS_POLL(event)) {
-			struct acpi_polling_hotkey *key;
-			key = (struct acpi_polling_hotkey *)
-			    get_hotkey_by_event(hotkey_list, event);
-			read_acpi_int(handle, method, key->poll_result);
+			if ( method_type == POLL_METHOD )
+				read_acpi_int(key->poll_hotkey.poll_handle,
+					key->poll_hotkey.poll_method,
+					key->poll_hotkey.poll_result);
+			else if ( method_type == ACTION_METHOD )
+				write_acpi_int(key->poll_hotkey.action_handle,
+					key->poll_hotkey.action_method, value, NULL);
+			else
+				goto do_fail;
+
 		}
 	} else {
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Not supported"));
 		return_VALUE(-EINVAL);
 	}
-
 	return_VALUE(count);
+do_fail:
+	return_VALUE(-EINVAL);
+
 }
 
 static int __init hotkey_init(void)
@@ -928,7 +1013,7 @@ static int __init hotkey_init(void)
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 				  "Hotkey: Unable to create %s entry\n",
 				  HOTKEY_EV_CONFIG));
-		return (-ENODEV);
+		goto do_fail1;
 	} else {
 		hotkey_config->proc_fops = &hotkey_config_fops;
 		hotkey_config->data = &global_hotkey_list;
@@ -943,7 +1028,8 @@ static int __init hotkey_init(void)
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 				  "Hotkey: Unable to create %s entry\n",
 				  HOTKEY_EV_CONFIG));
-		return (-ENODEV);
+
+		goto do_fail2;
 	} else {
 		hotkey_poll_config->proc_fops = &hotkey_poll_config_fops;
 		hotkey_poll_config->data = &global_hotkey_list;
@@ -957,7 +1043,7 @@ static int __init hotkey_init(void)
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 				  "Hotkey: Unable to create %s entry\n",
 				  HOTKEY_ACTION));
-		return (-ENODEV);
+		goto do_fail3;
 	} else {
 		hotkey_action->proc_fops = &hotkey_action_fops;
 		hotkey_action->owner = THIS_MODULE;
@@ -970,7 +1056,7 @@ static int __init hotkey_init(void)
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
 				  "Hotkey: Unable to create %s entry\n",
 				  HOTKEY_INFO));
-		return (-ENODEV);
+		goto do_fail4;
 	} else {
 		hotkey_info->proc_fops = &hotkey_info_fops;
 		hotkey_info->owner = THIS_MODULE;
@@ -979,23 +1065,33 @@ static int __init hotkey_init(void)
 	}
 
 	result = acpi_bus_register_driver(&hotkey_driver);
-	if (result < 0) {
-		remove_proc_entry(HOTKEY_PROC, acpi_root_dir);
-		return (-ENODEV);
-	}
+	if (result < 0)
+		goto do_fail5;
 	global_hotkey_list.count = 0;
 	global_hotkey_list.entries = &hotkey_entries;
 
 	INIT_LIST_HEAD(&hotkey_entries);
 
 	return (0);
+
+do_fail5:
+	remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir);
+do_fail4:
+	remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir);
+do_fail3:
+	remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir);
+do_fail2:
+	remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir);
+do_fail1:
+	remove_proc_entry(HOTKEY_PROC, acpi_root_dir);
+	return (-ENODEV);
 }
 
 static void __exit hotkey_exit(void)
 {
 	struct list_head *entries, *next;
 
-	ACPI_FUNCTION_TRACE("hotkey_remove");
+	ACPI_FUNCTION_TRACE("hotkey_exit");
 
 	list_for_each_safe(entries, next, global_hotkey_list.entries) {
 		union acpi_hotkey *key =
diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c
index 61ea70742d49..2934475d67d6 100644
--- a/drivers/acpi/motherboard.c
+++ b/drivers/acpi/motherboard.c
@@ -43,7 +43,7 @@ ACPI_MODULE_NAME		("acpi_motherboard")
  */
 #define IS_RESERVED_ADDR(base, len) \
 	(((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \
-	&& ((base) + (len) > PCIBIOS_MIN_IO))
+	&& ((base) + (len) > 0x1000))
 
 /*
  * Clearing the flag (IORESOURCE_BUSY) allows drivers to use
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index bdd9f37f8101..7289da3c4db6 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -145,10 +145,14 @@ acpi_os_vprintf(const char *fmt, va_list args)
 #endif
 }
 
+extern int acpi_in_resume;
 void *
 acpi_os_allocate(acpi_size size)
 {
-	return kmalloc(size, GFP_KERNEL);
+	if (acpi_in_resume)
+		return kmalloc(size, GFP_ATOMIC);
+	else
+		return kmalloc(size, GFP_KERNEL);
 }
 
 void
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index d1f42b972821..bb973d2109a1 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -269,7 +269,51 @@ acpi_pci_irq_del_prt (int segment, int bus)
 /* --------------------------------------------------------------------------
                           PCI Interrupt Routing Support
    -------------------------------------------------------------------------- */
+typedef int (*irq_lookup_func)(struct acpi_prt_entry *, int *, int *, char **);
 
+static int
+acpi_pci_allocate_irq(struct acpi_prt_entry *entry,
+	int	*edge_level,
+	int	*active_high_low,
+	char	**link)
+{
+	int	irq;
+
+	ACPI_FUNCTION_TRACE("acpi_pci_allocate_irq");
+
+	if (entry->link.handle) {
+		irq = acpi_pci_link_allocate_irq(entry->link.handle,
+			entry->link.index, edge_level, active_high_low, link);
+		if (irq < 0) {
+			ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ link routing entry\n"));
+			return_VALUE(-1);
+		}
+	} else {
+		irq = entry->link.index;
+		*edge_level = ACPI_LEVEL_SENSITIVE;
+		*active_high_low = ACPI_ACTIVE_LOW;
+	}
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq));
+	return_VALUE(irq);
+}
+
+static int
+acpi_pci_free_irq(struct acpi_prt_entry *entry,
+	int	*edge_level,
+	int	*active_high_low,
+	char	**link)
+{
+	int	irq;
+
+	ACPI_FUNCTION_TRACE("acpi_pci_free_irq");
+	if (entry->link.handle) {
+		irq = acpi_pci_link_free_irq(entry->link.handle);
+	} else {
+		irq = entry->link.index;
+	}
+	return_VALUE(irq);
+}
 /*
  * acpi_pci_irq_lookup
  * success: return IRQ >= 0
@@ -282,12 +326,13 @@ acpi_pci_irq_lookup (
 	int			pin,
 	int			*edge_level,
 	int			*active_high_low,
-	char			**link)
+	char			**link,
+	irq_lookup_func		func)
 {
 	struct acpi_prt_entry	*entry = NULL;
 	int segment = pci_domain_nr(bus);
 	int bus_nr = bus->number;
-	int irq;
+	int ret;
 
 	ACPI_FUNCTION_TRACE("acpi_pci_irq_lookup");
 
@@ -301,22 +346,8 @@ acpi_pci_irq_lookup (
 		return_VALUE(-1);
 	}
 	
-	if (entry->link.handle) {
-		irq = acpi_pci_link_get_irq(entry->link.handle,
-			entry->link.index, edge_level, active_high_low, link);
-		if (irq < 0) {
-			ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ link routing entry\n"));
-			return_VALUE(-1);
-		}
-	} else {
-		irq = entry->link.index;
-		*edge_level = ACPI_LEVEL_SENSITIVE;
-		*active_high_low = ACPI_ACTIVE_LOW;
-	}
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq));
-
-	return_VALUE(irq);
+	ret = func(entry, edge_level, active_high_low, link);
+	return_VALUE(ret);
 }
 
 /*
@@ -330,7 +361,8 @@ acpi_pci_irq_derive (
 	int			pin,
 	int			*edge_level,
 	int			*active_high_low,
-	char			**link)
+	char			**link,
+	irq_lookup_func		func)
 {
 	struct pci_dev		*bridge = dev;
 	int			irq = -1;
@@ -363,7 +395,7 @@ acpi_pci_irq_derive (
 		}
 
 		irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn),
-			pin, edge_level, active_high_low, link);
+			pin, edge_level, active_high_low, link, func);
 	}
 
 	if (irq < 0) {
@@ -415,7 +447,7 @@ acpi_pci_irq_enable (
 	 * values override any BIOS-assigned IRQs set during boot.
 	 */
  	irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
-		&edge_level, &active_high_low, &link);
+		&edge_level, &active_high_low, &link, acpi_pci_allocate_irq);
 
 	/*
 	 * If no PRT entry was found, we'll try to derive an IRQ from the
@@ -423,7 +455,7 @@ acpi_pci_irq_enable (
 	 */
 	if (irq < 0)
  		irq = acpi_pci_irq_derive(dev, pin, &edge_level,
-			&active_high_low, &link);
+			&active_high_low, &link, acpi_pci_allocate_irq);
  
 	/*
 	 * No IRQ known to the ACPI subsystem - maybe the BIOS / 
@@ -462,7 +494,9 @@ acpi_pci_irq_enable (
 EXPORT_SYMBOL(acpi_pci_irq_enable);
 
 
-#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
+/* FIXME: implement x86/x86_64 version */
+void __attribute__((weak)) acpi_unregister_gsi(u32 i) {}
+
 void
 acpi_pci_irq_disable (
 	struct pci_dev		*dev)
@@ -489,14 +523,14 @@ acpi_pci_irq_disable (
 	 * First we check the PCI IRQ routing table (PRT) for an IRQ.
 	 */
  	gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
-				  &edge_level, &active_high_low, NULL);
+			&edge_level, &active_high_low, NULL, acpi_pci_free_irq);
 	/*
 	 * If no PRT entry was found, we'll try to derive an IRQ from the
 	 * device's parent bridge.
 	 */
 	if (gsi < 0)
  		gsi = acpi_pci_irq_derive(dev, pin,
-					  &edge_level, &active_high_low, NULL);
+			&edge_level, &active_high_low, NULL, acpi_pci_free_irq);
 	if (gsi < 0)
 		return_VOID;
 
@@ -512,4 +546,3 @@ acpi_pci_irq_disable (
 
 	return_VOID;
 }
-#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 6ad0e77df9b3..834c2ceff1aa 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -68,6 +68,10 @@ static struct acpi_driver acpi_pci_link_driver = {
 			},
 };
 
+/*
+ * If a link is initialized, we never change its active and initialized
+ * later even the link is disable. Instead, we just repick the active irq
+ */
 struct acpi_pci_link_irq {
 	u8			active;			/* Current IRQ */
 	u8			edge_level;		/* All IRQs */
@@ -76,8 +80,7 @@ struct acpi_pci_link_irq {
 	u8			possible_count;
 	u8			possible[ACPI_PCI_LINK_MAX_POSSIBLE];
 	u8			initialized:1;
-	u8			suspend_resume:1;
-	u8			reserved:6;
+	u8			reserved:7;
 };
 
 struct acpi_pci_link {
@@ -85,12 +88,14 @@ struct acpi_pci_link {
 	struct acpi_device	*device;
 	acpi_handle		handle;
 	struct acpi_pci_link_irq irq;
+	int			refcnt;
 };
 
 static struct {
 	int			count;
 	struct list_head	entries;
 }				acpi_link;
+DECLARE_MUTEX(acpi_link_lock);
 
 
 /* --------------------------------------------------------------------------
@@ -532,12 +537,12 @@ static int acpi_pci_link_allocate(
 
 	ACPI_FUNCTION_TRACE("acpi_pci_link_allocate");
 
-	if (link->irq.suspend_resume) {
-		acpi_pci_link_set(link, link->irq.active);
-		link->irq.suspend_resume = 0;
-	}
-	if (link->irq.initialized)
+	if (link->irq.initialized) {
+		if (link->refcnt == 0)
+			/* This means the link is disabled but initialized */
+			acpi_pci_link_set(link, link->irq.active);
 		return_VALUE(0);
+	}
 
 	/*
 	 * search for active IRQ in list of possible IRQs.
@@ -596,13 +601,13 @@ static int acpi_pci_link_allocate(
 }
 
 /*
- * acpi_pci_link_get_irq
+ * acpi_pci_link_allocate_irq
  * success: return IRQ >= 0
  * failure: return -1
  */
 
 int
-acpi_pci_link_get_irq (
+acpi_pci_link_allocate_irq (
 	acpi_handle		handle,
 	int			index,
 	int			*edge_level,
@@ -613,7 +618,7 @@ acpi_pci_link_get_irq (
 	struct acpi_device	*device = NULL;
 	struct acpi_pci_link	*link = NULL;
 
-	ACPI_FUNCTION_TRACE("acpi_pci_link_get_irq");
+	ACPI_FUNCTION_TRACE("acpi_pci_link_allocate_irq");
 
 	result = acpi_bus_get_device(handle, &device);
 	if (result) {
@@ -633,21 +638,81 @@ acpi_pci_link_get_irq (
 		return_VALUE(-1);
 	}
 
-	if (acpi_pci_link_allocate(link))
+	down(&acpi_link_lock);
+	if (acpi_pci_link_allocate(link)) {
+		up(&acpi_link_lock);
 		return_VALUE(-1);
+	}
 	   
 	if (!link->irq.active) {
+		up(&acpi_link_lock);
 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link active IRQ is 0!\n"));
 		return_VALUE(-1);
 	}
+	link->refcnt ++;
+	up(&acpi_link_lock);
 
 	if (edge_level) *edge_level = link->irq.edge_level;
 	if (active_high_low) *active_high_low = link->irq.active_high_low;
 	if (name) *name = acpi_device_bid(link->device);
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+		"Link %s is referenced\n", acpi_device_bid(link->device)));
 	return_VALUE(link->irq.active);
 }
 
+/*
+ * We don't change link's irq information here.  After it is reenabled, we
+ * continue use the info
+ */
+int
+acpi_pci_link_free_irq(acpi_handle handle)
+{
+	struct acpi_device	*device = NULL;
+	struct acpi_pci_link	*link = NULL;
+	acpi_status		result;
+
+	ACPI_FUNCTION_TRACE("acpi_pci_link_free_irq");
+
+	result = acpi_bus_get_device(handle, &device);
+	if (result) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n"));
+		return_VALUE(-1);
+	}
+
+	link = (struct acpi_pci_link *) acpi_driver_data(device);
+	if (!link) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
+		return_VALUE(-1);
+	}
+
+	down(&acpi_link_lock);
+	if (!link->irq.initialized) {
+		up(&acpi_link_lock);
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link isn't initialized\n"));
+		return_VALUE(-1);
+	}
 
+#ifdef	FUTURE_USE
+	/*
+	 * The Link reference count allows us to _DISable an unused link
+	 * and suspend time, and set it again  on resume.
+	 * However, 2.6.12 still has irq_router.resume
+	 * which blindly restores the link state.
+	 * So we disable the reference count method
+	 * to prevent duplicate acpi_pci_link_set()
+	 * which would harm some systems
+	 */
+	link->refcnt --;
+#endif
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+		"Link %s is dereferenced\n", acpi_device_bid(link->device)));
+
+	if (link->refcnt == 0) {
+		acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);
+	}
+	up(&acpi_link_lock);
+	return_VALUE(link->irq.active);
+}
 /* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
@@ -677,6 +742,7 @@ acpi_pci_link_add (
 	strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
 	acpi_driver_data(device) = link;
 
+	down(&acpi_link_lock);
 	result = acpi_pci_link_get_possible(link);
 	if (result)
 		goto end;
@@ -712,6 +778,7 @@ acpi_pci_link_add (
 end:
 	/* disable all links -- to be activated on use */
 	acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);
+	up(&acpi_link_lock);
 
 	if (result)
 		kfree(link);
@@ -720,24 +787,42 @@ end:
 }
 
 static int
-irqrouter_suspend(
-	struct sys_device *dev,
-	u32	state)
+acpi_pci_link_resume(
+	struct acpi_pci_link *link)
+{
+	ACPI_FUNCTION_TRACE("acpi_pci_link_resume");
+
+	if (link->refcnt && link->irq.active && link->irq.initialized)
+		return_VALUE(acpi_pci_link_set(link, link->irq.active));
+	else
+		return_VALUE(0);
+}
+
+/*
+ * FIXME: this is a workaround to avoid nasty warning.  It will be removed
+ * after every device calls pci_disable_device in .resume.
+ */
+int acpi_in_resume;
+static int
+irqrouter_resume(
+	struct sys_device *dev)
 {
 	struct list_head        *node = NULL;
 	struct acpi_pci_link    *link = NULL;
 
-	ACPI_FUNCTION_TRACE("irqrouter_suspend");
+	ACPI_FUNCTION_TRACE("irqrouter_resume");
 
+	acpi_in_resume = 1;
 	list_for_each(node, &acpi_link.entries) {
 		link = list_entry(node, struct acpi_pci_link, node);
 		if (!link) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
+			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+				"Invalid link context\n"));
 			continue;
 		}
-		if (link->irq.active && link->irq.initialized)
-			link->irq.suspend_resume = 1;
+		acpi_pci_link_resume(link);
 	}
+	acpi_in_resume = 0;
 	return_VALUE(0);
 }
 
@@ -756,8 +841,9 @@ acpi_pci_link_remove (
 
 	link = (struct acpi_pci_link *) acpi_driver_data(device);
 
-	/* TBD: Acquire/release lock */
+	down(&acpi_link_lock);
 	list_del(&link->node);
+	up(&acpi_link_lock);
 
 	kfree(link);
 
@@ -849,9 +935,10 @@ int __init acpi_irq_balance_set(char *str)
 __setup("acpi_irq_balance", acpi_irq_balance_set);
 
 
+/* FIXME: we will remove this interface after all drivers call pci_disable_device */
 static struct sysdev_class irqrouter_sysdev_class = {
         set_kset_name("irqrouter"),
-        .suspend = irqrouter_suspend,
+        .resume = irqrouter_resume,
 };
 
 
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 893b074e3d1a..2c04740c6543 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -81,30 +81,32 @@ module_param(bm_history, uint, 0644);
  *
  * To skip this limit, boot/load with a large max_cstate limit.
  */
-static int no_c2c3(struct dmi_system_id *id)
+static int set_max_cstate(struct dmi_system_id *id)
 {
 	if (max_cstate > ACPI_PROCESSOR_MAX_POWER)
 		return 0;
 
-	printk(KERN_NOTICE PREFIX "%s detected - C2,C3 disabled."
+	printk(KERN_NOTICE PREFIX "%s detected - limiting to C%ld max_cstate."
 		" Override with \"processor.max_cstate=%d\"\n", id->ident,
-	       ACPI_PROCESSOR_MAX_POWER + 1);
+		(long)id->driver_data, ACPI_PROCESSOR_MAX_POWER + 1);
 
-	max_cstate = 1;
+	max_cstate = (long)id->driver_data;
 
 	return 0;
 }
 
 
-
-
 static struct dmi_system_id __initdata processor_power_dmi_table[] = {
-	{ no_c2c3, "IBM ThinkPad R40e", {
+	{ set_max_cstate, "IBM ThinkPad R40e", {
 	  DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
-	  DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW") }},
-	{ no_c2c3, "Medion 41700", {
+	  DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW") }, (void*)1},
+	{ set_max_cstate, "Medion 41700", {
+	  DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
+	  DMI_MATCH(DMI_BIOS_VERSION,"R01-A1J") }, (void*)1},
+	{ set_max_cstate, "Clevo 5600D", {
 	  DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
-	  DMI_MATCH(DMI_BIOS_VERSION,"R01-A1J") }},
+	  DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307") },
+	  (void*)2},
 	{},
 };
 
@@ -549,7 +551,8 @@ static int acpi_processor_get_power_info_default_c1 (struct acpi_processor *pr)
 	ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_default_c1");
 
 	for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++)
-		memset(pr->power.states, 0, sizeof(struct acpi_processor_cx));
+		memset(&(pr->power.states[i]), 0, 
+		       sizeof(struct acpi_processor_cx));
 
 	/* if info is obtained from pblk/fadt, type equals state */
 	pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
@@ -580,7 +583,8 @@ static int acpi_processor_get_power_info_cst (struct acpi_processor *pr)
 
 	pr->power.count = 0;
 	for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++)
-		memset(pr->power.states, 0, sizeof(struct acpi_processor_cx));
+		memset(&(pr->power.states[i]), 0, 
+		       sizeof(struct acpi_processor_cx));
 
 	status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);
 	if (ACPI_FAILURE(status)) {
@@ -763,7 +767,6 @@ static void acpi_processor_power_verify_c3(
 	}
 
 	if (pr->flags.bm_check) {
-		printk("Disabling BM access before entering C3\n");
 		/* bus mastering control is necessary */
 		if (!pr->flags.bm_control) {
 			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -771,7 +774,6 @@ static void acpi_processor_power_verify_c3(
 			return_VOID;
 		}
 	} else {
-		printk("Invalidating cache before entering C3\n");
 		/*
 		 * WBINVD should be set in fadt, for C3 state to be
 		 * supported on when bm_check is not required.
@@ -842,7 +844,7 @@ static int acpi_processor_get_power_info (
 	result = acpi_processor_get_power_info_cst(pr);
 	if ((result) || (acpi_processor_power_verify(pr) < 2)) {
 		result = acpi_processor_get_power_info_fadt(pr);
-		if (result)
+		if ((result) || (acpi_processor_power_verify(pr) < 2))
 			result = acpi_processor_get_power_info_default_c1(pr);
 	}